
    l0jw                        d Z ddlZddlZddlZddlmZmZmZ ddl	m
Z
mZ ddlmZ ddlmZmZmZmZmZmZmZmZ 	 ddlmZmZ dd	lmZ nB# e$ r:Z ej        e          Z ej        e          Z ej        e          ZY dZ[ndZ[ww xY w	 ddlZ n"# e$ rZ ej        e          Z Y dZ[ndZ[ww xY wd*dZ!dee         fdZ"d Z#d Z$d Z%d Z&d+dee         fdZ'd,defdZ(d-dZ)d.dZ*dedee         fdZ+dededeeef         fdZ,d/dZ-d+dZ.d0d Z/d! Z0	 d1d#ee         d$ee         fd%Z1d.d&Z2d' Z3d.d(Z4d.d)Z5dS )2z
graph.py
-------------

Deal with graph operations. Primarily deal with graphs in (n, 2)
edge list form, and abstract the backend graph library being used.

Currently uses networkx or scipy.sparse.csgraph backend.
    N   )
exceptionsgroupingutil)logtol)faces_to_edges)	ArrayLikeListNDArrayNumberOptionalSequenceUnionint64)
coo_matrixcsgraph)cKDTreeFc                    |+t          | d          \  }}|                    d           n|j        }|j        }t	          j        |d          }t          |          dk    rt          j        d	           ||         }|dddf         |dddf         k    }||         }|                    d           |r>||dddf         |                  }t          |          t          |          k    sJ ||fS |S )
a  
    Returns an (n, 2) list of face indices.
    Each pair of faces in the list shares an edge, making them adjacent.


    Parameters
    -----------
    faces : (n, 3) int, or None
        Vertex indices representing triangles
    mesh : Trimesh object
        If passed will used cached edges
        instead of generating from faces
    return_edges : bool
        Return the edges shared by adjacent faces

    Returns
    ----------
    adjacency : (m, 2) int
        Indexes of faces that are adjacent
    edges: (m, 2) int
        Only returned if return_edges is True
        Indexes of vertices which make up the
        edges shared by the adjacent faces

    Examples
    ----------
    This is useful for lots of things such as finding
    face- connected components:
    ```python
    >>> graph = nx.Graph()
    >>> graph.add_edges_from(mesh.face_adjacency)
    >>> groups = nx.connected_components(graph_connected)
    ```
    NT)return_indexr   axis   require_countr   z3No adjacent faces detected! Did you merge vertices?)	r	   sortedges_sorted
edges_facer   
group_rowslenr   debug)	facesmeshreturn_edgesedgesr   edge_groups	adjacencynondegenerateadjacency_edgess	            P/home/wildlama/miniconda3/envs/lam/lib/python3.11/site-packages/trimesh/graph.pyface_adjacencyr+   &   s*   H | +5tDDDz


 !_
 %e1===K
;1	GHHH
 ;'I aaadOyA6M-(I NNN *AAAqD 1- @A?##s9~~5555/))    returnc                 $   | j         }|j        |z  }|                    d           |                                 |                                }t          j        |j        dddf         |j        dddf         fdt
          j	                  }|S )a  
    Find faces that share a vertex i.e. 'neighbors' faces.
    Relies on the fact that an adjacency matrix at a power p
    contains the number of paths of length p connecting two nodes.
    Here we take the bipartite graph from mesh.faces_sparse to the power 2.
    The non-zeros are the faces connected by one vertex.

    Returns
    ----------
    neighborhood : (n, 2) int
        Pairs of faces which share a vertex
    r   N)r   dtype)
faces_sparseTsetdiageliminate_zerostocoonpconcatenaterowcolr   )r#   VTTTneighborhoods       r*   face_neighborhoodr=   t   s     
	B	BJJqMMM	B>	4"&D/*28  L r,   c           
         t          j        | j        t           j                  dz
  }| j        }t          | j        j                  D ]\  }}| j        |         }t          j        t          j	        ||dddf         
                    d          k    ||dddf         
                    d          k                        }|                    d          dk    }d|| ddf<   ||         |||f<   |S )a  
    Return the vertex index of the two vertices not in the shared
    edge between two adjacent faces

    Parameters
    ----------
    mesh : Trimesh object
      Input mesh

    Returns
    -----------
    vid_unshared : (len(mesh.face_adjacency), 2) int
      Indexes of mesh.vertices
      for degenerate faces without exactly
      one unshared vertex per face it will be -1
    r0   r   Nr   r/   r   r   F)r6   
zeros_liker+   r   face_adjacency_edges	enumerater2   r"   logical_not
logical_orreshapesum)r#   vid_unsharedr%   ifidr"   unsharedrow_oks           r*   face_adjacency_unsharedrM      s   ( =!4BHEEEIL%E D/122 2 23
3 >Mqqq!t,,W555qqq!t,,W555 
 
 1%%*$&!!!"'/VQYr,   c                    | j         t          j        d          k    }t          j        dt          j        | j         |                   z            }| j        | j                 }t          j        |d                              d          }| j	        }t          j        t          j        | j        |         d                              d                    }t          j        |t          j        ||                              d          |z            }t          j        |          }t          j        t!          | j                            t          j        z  }	||         |z  |	|<   |	|fS )a  
    Compute an approximate radius between adjacent faces.

    Parameters
    --------------
    mesh : trimesh.Trimesh

    Returns
    -------------
    radii : (len(self.face_adjacency),) float
      Approximate radius between faces
      Parallel faces will have a value of np.inf
    span :  (len(self.face_adjacency),) float
      Perpendicular projection distance of two
      unshared vertices onto the shared edge
    g{Gz?g       @r   r   )r/      r@   )face_adjacency_anglesr6   radiansabssinverticesrM   diffrF   rB   r   unitizesubtractdiagonal_dotrow_normonesr    r+   inf)
r#   nonzerodenominatorpoint_pairsvectorsr%   	edges_vecperpspanradiis
             r*   face_adjacency_radiusrd      s9   , (2:d+;+;;G&rvd&@&IJJJKKK - <=Kgk***227;;G %ERWT]5%9BBBJJ7SSTTI ;$#GY77??HH9T D =D GC+,,--6E'][0E'N$;r,   c                 `    t          j                    }|                    | j                   |S )a/  
    Returns a networkx graph representing the vertices and
    their connections in the mesh.

    Parameters
    ----------
    mesh : Trimesh object

    Returns
    ---------
    graph : networkx.Graph
        Graph representing vertices and edges between
        them where vertices are nodes and edges are edges

    Examples
    ----------
    This is useful for getting nearby vertices for a given vertex,
    potentially for some simple smoothing techniques.
    >>> graph = mesh.vertex_adjacency_graph
    >>> graph.neighbors(0)
    > [1, 3, 4]
    )nxGraphadd_edges_fromedges_unique)r#   gs     r*   vertex_adjacency_graphrk      s+    . 	

AT&'''Hr,   c                     t          j        t          |           d          }t          j        t          |          d          }t          j        ||t           j                  }|S )a  
    Given two sets of faces, find the edges which are in both sets.

    Parameters
    ---------
    faces_a : (n, 3) int
      Array of faces
    faces_b : (m, 3) int
      Array of faces

    Returns
    ---------
    shared : (p, 2) int
      Edges shared between faces
    r   r   	operation)r6   r   r	   r   boolean_rowsintersect1d)faces_afaces_be_ae_bshareds        r*   shared_edgesrv     sZ      '.))
2
2
2C
'.))
2
2
2C"3r~FFFFMr,   facet_thresholdc                    |t           j        }| j        }| j        }t	          j        t          |          t                    }t	          j        |          t           j	        k    }||         ||         z  dz  |k    ||<   t          | j        |         t	          j        t          | j                            d|          }|S )a  
    Find the list of parallel adjacent faces.

    Parameters
    -----------
    mesh : trimesh.Trimesh
    engine : str
      Which graph engine to use:
      ('scipy', 'networkx')
    facet_threshold : float
      Threshold for two facets to be considered coplanar

    Returns
    ---------
    facets : sequence of (n,) int
        Groups of face indexes of
        parallel adjacent faces.
    Nr?   r   )nodesmin_lenengine)r   rw   rd   face_adjacency_spanr6   rZ   r    boolrR   zeroconnected_componentsr+   aranger"   )r#   r{   rw   rc   rb   parallelr\   
componentss           r*   facetsr     s    & - &E#D ws5zz...HfTllSX%Gw$w-7A=OHW &H%iDJ((	  J r,   Tc                     || j         }|rd}nd}t          |t          j        t	          | j                            ||          } | j        |fd|i|}|S )a#  
    Split a mesh into multiple meshes from face
    connectivity.

    If only_watertight is true it will only return
    watertight meshes and will attempt to repair
    single triangle or quad holes.

    Parameters
    ----------
    mesh : trimesh.Trimesh
    only_watertight: bool
      Only return watertight components
    adjacency : (n, 2) int
      Face adjacency to override full mesh
    engine : str or None
      Which graph engine to use

    Returns
    ----------
    meshes : (m,) trimesh.Trimesh
      Results of splitting
    N   r   )r%   ry   rz   r{   only_watertight)r+   r   r6   r   r    r"   submesh)r#   r   r'   r{   kwargsrz   r   meshess           r*   splitr   P  s}    0 '	  %ryTZ997SY  J T\*PPoPPPFMr,   c                      fd} fd}t          j         t           j                   t          j                   t	                    dk    rg S t	                     dk    r/dk    r't          j        d                                          S g S t          j         d          st          d	          dg}t	                     dk    r'|
                                                                t	                    dk    r'|
                                                               t          j        |          dz   t          j        t                    }d
|<   |                              d          } |          t          j        d|fd|ff          }	||	v r |	|                     S |	                                D ]}
	  |
            c S # t$          $ r Y w xY wt'          d          )a  
    Find groups of connected nodes from an edge list.

    Parameters
    -----------
    edges : (n, 2) int
      Edges between nodes
    nodes : (m, ) int or None
      List of nodes that exist
    min_len : int
      Minimum length of a component group to return
    engine :  str or None
      Which graph engine to use (None for automatic):
      (None, 'networkx', 'scipy')


    Returns
    -----------
    components : (n,) sequence of (*,) int
      Nodes which are connected
    c                      t          j                  } dk    r|                                d t          j        |           D             S )z:
        Find connected components using networkx
        r   c                 ,    g | ]}t          |          S  list.0rI   s     r*   
<listcomp>zEconnected_components.<locals>.components_networkx.<locals>.<listcomp>  s    @@@AQ@@@r,   )rf   from_edgelistadd_nodes_fromr   )graphr%   rz   ry   s    r*   components_networkxz1connected_components.<locals>.components_networkx  sS      '' a<<  '''@@!8!?!?@@@@r,   c                     t                    } t          j        t                    }d|<   t          j        t          j                  |         t          j        | |                   }fd|D             S )zF
        Find connected components using scipy.sparse.csgraph
        )
node_countr?   T)rz   c                      g | ]
}|         S r   r   )r   cindexs     r*   r   zDconnected_components.<locals>.components_csgraph.<locals>.<listcomp>  s    ---Qa---r,   )connected_component_labelsr6   zerosr}   r   r   r   group)labels	containedr   r   r%   rz   r   ry   s      @r*   components_csgraphz0connected_components.<locals>.components_csgraph  s    
 ,EjIII HZt444		%	*BH555i@^F9$5wGGG
----*----r,   r?   Nr   r   r@   r/   r   edges must be (n, 2)!Tr   scipynetworkxzno graph engines available!)r6   
asanyarrayr   uniquer    rF   tolistr   is_shape
ValueErrorappendmaxr   r}   allcollectionsOrderedDictvaluesBaseExceptionImportError)r%   rz   ry   r{   r   r   countsmaskedges_okenginesfunctionr   s   ```        @r*   r   r   x  sL   .	A 	A 	A 	A 	A 	A 	A       $ M%rx000E}	%   5zzQ		Uqa<<:eW--44666I=(( 20111 SF
5zzA~~eiikk"""
5zzA~~eiikk"""!#J 8Jd+++DDKE{A&&H(OE %
%	&5H(IJ G
 wv    NN$$  	8:: 	 	 	H	
3
4
44s   	G((
G54G5c                     t          | |          }t          j        |d          \  }}|t          |          |k    sJ |S )a?  
    Label graph nodes from an edge list, using scipy.sparse.csgraph

    Parameters
    -----------
    edges : (n, 2) int
       Edges of a graph
    node_count : int, or None
        The largest node in the graph.

    Returns
    ----------
    labels : (node_count,) int
        Component labels for each node
    F)directed)edges_to_coor   r   r    )r%   r   matrix_body_countr   s        r*   r   r     sO      %,,F!6vNNNK6{{j((((Mr,   	traversalc           	      .  	 t          j        | dd         | dd         f          	                    t          j        	d                    d         dk     }|                                r| g}n%t          j        |dd          }	fd	|D             }t          j        fd
|D                       }|                                rJt          j	        |          d         D ]/}t          j
        ||         ||         dd         g          ||<   0t          j        rr|D ]o}t          j        t          j        |dd         |dd         f          d          }                    |          d         dk                                     sJ p|S )a  
    Given a traversal as a list of nodes split the traversal
    if a sequential index pair is not in the given edges.
    Useful since the implementation of DFS we're using will
    happily return disconnected values in a flat traversal.

    Parameters
    --------------
    traversal : (m,) int
       Traversal through edges
    edges_tree : cKDTree
      A way to reconstruct original edge indices from
      sorted (n, 2) edge values. This is a slight misuse of a
      kdtree since one could just hash the tuples of the integer
      edges, but that isn't possible with numpy arrays easily
      and this allows a vectorized reconstruction.

    Returns
    ---------------
    split : sequence of (p,) int
      Traversals split into only connected paths.
    Nr/   r   r   r   绽|=T)rz   only_nonzeroc                     g | ]<}t          j        d d df         |         |d                  dd          g          =S )Nr   r/   r   )r6   r7   )r   b	trav_edges     r*   r   z$_split_traversal.<locals>.<listcomp>  sX     
 
 
KLBNIaaadOA.	!B%0@0DEFF
 
 
r,   c           	          g | ]a}t          |          d k    oK|d         |d         k    o9                    t          |d         |d         g                    d         dk     bS )r   r   r/   r   )r    querysorted)r   s
edges_trees     r*   r   z$_split_traversal.<locals>.<listcomp>#  s     	
 	
 	
  FFQJ C!"C  1qu!6!677:UB	
 	
 	
r,   )r6   column_stackr   r   r   r   blocksarrayanyr\   r7   r   strict)
r   r   existsr   r   needs_closerI   r   
check_edger   s
    `       @r*   _split_traversalr     s   2 3B3122 ?@@I bgia88899!<uDFzz|| 
 FFF
 
 
 
PV
 
 
 (	
 	
 	
 	
 		
 	
 	
 K  @K((+ 	@ 	@A~uQxq"1"&>??E!HH
z C 	C 	CA!CRC&!ABB%!A!AJJJJ$$Z003e;@@BBBBBBLr,   
traversalsr%   c                    t          j        |d          }t          |          }t          |           dk    r|                                S g }| D ]&}|                    t          ||                     't          j        d |D                       }t          |          dk    rK|                    d           |                    t          j
        ||t           j                             n|                                }|S )a  
    Convert a traversal of a list of edges into a sequence of
    traversals where every pair of consecutive node indexes
    is an edge in a passed edge list

    Parameters
    -------------
    traversals : sequence of (m,) int
       Node indexes of traversals of a graph
    edges : (n, 2) int
       Pairs of connected node indexes

    Returns
    --------------
    splits : sequence of (p,) int
       Node indexes of connected traversals
    r   r   r   )r   r   c                 Z    g | ](}t          j        |d d         |dd          f          )S )Nr/   r   )r6   r   r   s     r*   r   z#fill_traversals.<locals>.<listcomp>W  s6    !S!S!Sq"/1SbS61QRR5/"B"B!S!S!Sr,   rm   )r6   r   r   r    copyextendr   r   vstack_emptyr   ro   	setdiff1d)r   r%   r   splitsry   includeds         r*   fill_traversalsr   7  s   & GE"""EJ :!zz||F P P&:NNNOOOO  !S!SF!S!S!STTH
8}}q1 	h+E8r|TTTUUUU Mr,   bfsc                 :   t          j        | t           j                  } t          |           dk    rg S t	          j        | d          st          d          t          |                                          	                                }|dk    rt          j        }n"|dk    rt          j        }nt          d          |                     d	           t          |                     d
                    }t!          |           }g }t          |          dk    r}|                                } |||dd                              t           j                  }|                    |           |                    |           t          |          dk    }|S )a  
    Given an edge list generate a sequence of ordered depth
    first search traversals using scipy.csgraph routines.

    Parameters
    ------------
    edges : (n, 2) int
      Undirected edges of a graph
    mode :  str
      Traversal type, 'bfs' or 'dfs'

    Returns
    -----------
    traversals : (m,) sequence of (p,) int
      Ordered DFS or BFS traversals of the graph.
    r?   r   r   zedges are not (n, 2)!r   dfsz(traversal mode must be either dfs or bfsr   r   r/   F)i_startreturn_predecessorsr   )r6   r   r   r    r   r   r   strlowerstripr   breadth_first_orderdepth_first_orderr   setrF   r   popastyper   difference_update)r%   modefuncry   r   r   startordereds           r*   r   r   f  s|   " HU"(+++E
5zzQ	]5'** 20111 t99??""$$Du}}*	(CDDD 
JJAJb!!""EE J
e**q..		$5ee
 
 

&

 	 	'"""((( e**q.. r,   c                    t          j        | t           j                  } t          |           dk    s$t	          j        | d          st          d          ||                                 dz   }t          |          }|(t          j	        t          |           t                    }t          || j        f|j        ||f          }|S )a  
    Given an edge list, return a boolean scipy.sparse.coo_matrix
    representing the edges in matrix form.

    Parameters
    ------------
    edges : (n, 2) int
      Edges of a graph
    count : int
      The total number of nodes in the graph
      if None: count = edges.max() + 1
    data : (n,) any
      Assign data to each edge, if None will
      be bool True for each specified edge

    Returns
    ------------
    matrix: (count, count) scipy.sparse.coo_matrix
      Sparse COO
    r?   r   r   r   Nr   )r0   shape)r6   r   r   r    r   r   r   r   intrZ   r}   r   r2   r0   )r%   countdatar   s       r*   r   r     s    * M%rx000EJJ!OOt}UG<<O0111 }		aJJE |ws5zz...uwtz%PPPFMr,   c                     t          j        t                    |rfd| D              nfd| D              ||                                 dz   }fdt	          |          D             }|S )a  
    Find the neighbors for each node in an edgelist graph.

    TODO : re-write this with sparse matrix operations

    Parameters
    ------------
    edges : (n, 2) int
      Connected nodes
    directed : bool
      If True, only connect edges in one direction

    Returns
    ---------
    neighbors : sequence
      Vertex index corresponds to set of other vertex indices
    c                 ^    g | ])}|d                                        |d                   *S r   r   addr   edge	neighborss     r*   r   zneighbors.<locals>.<listcomp>  s4    ;;;T47			Q	(	(;;;r,   c                     g | ]P}|d                                        |d                   |d                                       |d                    fQS r   r   r   s     r*   r   zneighbors.<locals>.<listcomp>  sd     	
 	
 	
 tAw##DG,,iQ.@.D.DT!W.M.MN	
 	
 	
r,   Nr   c                 :    g | ]}t          |                   S r   r   )r   rI   r   s     r*   r   zneighbors.<locals>.<listcomp>  s%    :::AT)A,:::r,   )r   defaultdictr   r   range)r%   	max_indexr   r   r   s       @r*   r   r     s    $ ',,I 
;;;;U;;;;;	
 	
 	
 	
	
 	
 	
 	

 IIKK!O	::::y)9)9:::ELr,   c                  R    t          j        dt          d           t          | i |S )zA
    DEPRECATED: use `trimesh.graph.smooth_shade(mesh, ...)`
    zu`trimesh.graph.smoothed` is deprecated and will be removed in March 2024: use `trimesh.graph.smooth_shade(mesh, ...)`r   )category
stacklevel)warningswarnDeprecationWarningsmooth_shade)argsr   s     r*   smoothedr	    s=     M	8#	    ((((r,         $@anglefacet_minareac                 X   |t          j        d          }t          | j                  dk    r|                                 S | j        |k     }| j        |         }g }d}|| j        | j        |z  	 fd| j        D             }t          |          dk    rzt          j	        t          | j
                  t                    }d|t          j        |          <   |||                             d                   }t          j        |          }n&# t          $ r t!          j        d	d
           Y nw xY wt%          |d|          }t          |          dk    r|                    |           t          |          dk    r|                                 S t          j        t          j        |                    }	t          |	          t          | j
                  k    rat          j        t          j        t          | j
                            |	          }
|                    |
                    d                     |                     |dd
          }||j        d<   t          |j
                  t          | j
                  k    rt!          j        d           |S )az  
    Return a non-watertight version of the mesh which
    will render nicely with smooth shading by
    disconnecting faces at sharp angles to each other.

    Parameters
    -----------
    mesh : trimesh.Trimesh
      Source geometry
    angle : float or None
      Angle in radians face pairs with angles
      smaller than this will appear smoothed
    facet_minarea : float or None
      Minimum area fraction to consider
      IE for `facets_minarea=25` only facets larger
      than `mesh.area / 25` will be considered.

    Returns
    ---------
    smooth : trimesh.Trimesh
      Geometry with disconnected face patches
    N   r   c                 P    g | ]"}|                                          k     |#S r   )rG   )r   fareasmin_areas     r*   r   z smooth_shade.<locals>.<listcomp>&  s/    JJJAa0I0Ia0I0I0Ir,   r?   Fr   r   zfailed to calculate facetsT)exc_infor   )rz   ry   r@   )r   r   original_componentszface count in smooth wrong!)r6   rQ   r    r+   r   rP   
area_facesarear   rZ   r"   r}   hstackr   r   r   r   warningr   r   r   r   rF   r   metadata)r#   r  r  angle_okr'   r   ry   r   r   r   brokesmoothr  r  s               @@r*   r  r    s   2 }
2 41$$yy{{ )E1H#H-I FE 9},	E KJJJJJJJF6{{Q ws4:d;;;*/RYv&&'%d9o&9&9q&9&A&AB		),, 	E 	E 	EK4tDDDDDD	E &i%HHHJ 6{{Q&!!!
:! yy{{ Yry,,--F
6{{c$*oo%% RYs4:77@@%--00111 \\*eD\IIF-7FO)*
6<C
OO++1222Ms   5B!D  D:9D:c                 x   |t          j        | d          }t          j        |d          }t	          t          |          dz  t          |           k              }| |                             d          ddddf         j        }t	          t          j        | 	                                          }||fS )ah  
    Parameters
    -----------
    edges : (n, 2) int
      List of vertex indices
    edges_sorted : (n, 2) int
      Pass vertex indices sorted on axis 1 as a speedup

    Returns
    ---------
    watertight : boolean
      Whether every edge is shared by an even
      number of faces
    winding : boolean
      Whether every shared edge is reversed
    Nr   r   r   r   )r/   r   rO   )
r6   r   r   r   r}   r    rF   r2   equalr   )r%   r   groups
watertightopposingwindings         r*   is_watertightr#  P  s    $ wu1---  Q???Fs6{{Q3u::566J V}$$W--aaa1f57H28X&**,,--Gwr,   c                     ddl }ddl}|                                5 }t          j        j                            | |j                   |                    d|j        dg          }ddd           n# 1 swxY w Y   |S )z
    Turn a networkx graph into an SVG string
    using graphviz `dot`.

    Parameters
    ----------
    graph: networkx graph

    Returns
    ---------
    svg: string, pictoral layout in SVG format
    r   Ndotz-Tsvg)	
subprocesstempfileNamedTemporaryFilerf   drawing	nx_agraph	write_dotnamecheck_output)r   r&  r'  dot_filesvgs        r*   graph_to_svgr0  q  s     OOO		$	$	&	& G(

&&uhm<<<%%uhmW&EFFG G G G G G G G G G G G G G G Js   AA11A58A5c                    |Ft          |                                           t          |                                           z  dz   }|dfg}g }g }t          |          D ]}|d         d         }| |         }t          |          dk    r?|                    |           t          |          dk    r n|                                }jd}	|                                D ]^}
||
                                         D ]A}|	r|                    |
|f           d}	|                    |dd         |
|fgz              B_|S )a*  
    For a networkx MultiDiGraph, find all paths from a source node
    to leaf nodes. This function returns edge instance numbers
    in addition to nodes, unlike networkx.all_simple_paths.

    Parameters
    ---------------
    G : networkx.MultiDiGraph
      Graph to evaluate
    source : hashable
      Node to start traversal at
    cutoff : int
      Number of nodes to visit
      If None will visit all nodes

    Returns
    ----------
    traversals : (n,) list of [(node, edge instance index), ] paths
      Traversals of the multigraph
    Nr   r   r/   TF)r    r%   ry   r   r   r   keys)Gsourcecutoffcurrentqueuer   _current_nodechildr   nodeinstances               r*   multigraph_pathsr=    sn   * ~aggii..3qwwyy>>1Q6 {mGEJ6]] !H !H r{1~,u::?? g&&&5zzQ iikkGG E

 H H %d 0 0 2 2 H HH 
H  h'7888 % WSbS\dH5E4F%FGGGGHH r,   c                     g }t          j        |          D ]^\  }}| |d                  |d                  |d                  }||                    |           C|                    ||                    _|S )a\  
    Given a MultiDiGraph traversal, collect attributes along it.

    Parameters
    -------------
    G:          networkx.MultiDiGraph
    traversal:  (n) list of (node, instance) tuples
    attrib:     dict key, name to collect. If None, will return all

    Returns
    -------------
    collected: (len(traversal) - 1) list of attributes
    r   r   )r   pairwiser   )r3  r   attrib	collecteduvattribss          r*   multigraph_collectrE    s     Ii(( . .1AaD'!A$-!%>W%%%%WV_----r,   )NNF)NN)TNN)r   NN)N)r   )NF)Nr
  )6__doc__r   r  numpyr6    r   r   r   	constantsr   r   geometryr	   typedr
   r   r   r   r   r   r   r   scipy.sparser   r   scipy.spatialr   r   EExceptionWrapperr   rf   r+   r=   rM   rd   rk   rv   r   r   r   r   r   r   r   r   r   r	  r  r#  r0  r=  rE  r   r,   r*   <module>rP     s             ( ( ( ( ( ( ( ( ( (         $ $ $ $ $ $ U U U U U U U U U U U U U U U U U U U U000000000%%%%%%% 0 0 0)j)!,,G)j)!,,G,,Q//JJJJJJ	0( ( ( ( 
%	$Q	'	'BBBBBB(K K K K\wu~    2+ + +\. . .b  8  ,/ /x/? / / / /d% %PT % % % %Pd5 d5 d5 d5N   2< <W < < < <~, , ,uXwEV?W , , , ,^7 7 7 7t% % % %P   D
) 
) 
) MQV V&!V9A&9IV V V Vr   B  .A A A AH     s/   A B
0BB
B B2B--B2