Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
181 views
unlisted
ubuntu2004
a

��c<��@sdddlZddlmZddlmZddlmZddlmZddl	m
Z
ddlmZGdd	�d	e�Z
dS)
�N)�
SageObject)�matrix)�flatten)�
cached_method)�QQ)�lcmc@sVeZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Ze	dd
��Z
edd��Zedd��Z
edd��Zedd��Zedd��Zedd��Zedd��Zedd��Zdd�Zee	d d!���Zee	d"d#���Zd$d%�Zd&d'�Zd(d)�Ze	d*d+��Zd,d-�Zd.d/�Zd0d1�Zd2d3�Zd4d5�Zd6d7�Z d8d9�Z!dFd;d<�Z"d=d>�Z#ed?d@��Z$dAdB�Z%dCdD�Z&dES)G�EmbeddedLevelGrapha5
    LevelGraph inside a generalised stratum.

    Note that the points of the enveloping GeneralisedStratum are of the form
    (i,j) where i is the component and j the index of sig of that component,
    while the points of the level graph are numbers 1,...,n.

    Thus, dmp is a dictionary mapping integers to tuples of integers.

    Attributes:

    * LG (LevelGraph): underlying LevelGraph
    * X (GeneralisedStratum): enveloping stratum
    * dmp (dict): (bijective!) dictionary marked points of LG -> points of stratum
    * dmp_inv (dict): inverse of dmp
    * dlevels (dict): (bijective!) dictionary levels of LG -> new level numbering
    * dlevels_inv (dict): inverse of dlevels
    * top (GeneralisedStratum): (if self is a BIC) top component
    * bot (GeneralisedStratum): (if self is a BIC) bottom component
    * clutch_dict (dict): (if self is a BIC) dictionary mapping points of top
      stratum to points of bottom stratum where there is an edge in self.
    * emb_top (dict): (if self is a BIC) dictionary mapping points of stratum top
      to the corresponding points of the enveloping stratum.
    * emb_bot (dict): (if self is a BIC) dictionary mapping points of stratum bot
      to the corresponding points of the enveloping stratum.
    * automorphisms (list of list of dicts): automorphisms
    * codim (int): codimension of LevelGraph in stratum
      number_of_levels (int): Number of levels of self.

    Note that attempting to access any of the attributes top, bot, clutch_dict,
    emb_top or emb_bot will raise a ValueError if self is not a BIC.
    cCs�||_||_||_dd�|��D�|_|��||_dd�|��D�|_d|_d|_	d|_
d|_d|_d|_
i|_d|_|j��|_tt|j����|_dS)ag
        Initialises EmbeddedLevelGraph.

        Args:
            LG (LevelGraph): underlying LevelGraph
            X (GeneralisedStratum): enveloping stratum
            dmp (dictionary): (bijective!) dictionary marked points of LG -> points of stratum
            dlevels (dictionary): (bijective!) dictionary levels of LG -> new level numbering
        cSsi|]\}}||�qS�r	��.0�key�valuer	r	�K/home/user/Introduction lectures/admcycles/diffstrata/embeddedlevelgraph.py�
<dictcomp>:�z/EmbeddedLevelGraph.__init__.<locals>.<dictcomp>cSsi|]\}}||�qSr	r	r
r	r	rr=rN)�LG�X�dmp�items�dmp_inv�add_vertices_at_infinity�dlevelsZdlevels_inv�_top�_bot�_clutch_dict�_emb_top�_emb_bot�_automorphisms�_level�_ell�codim�len�set�keys�number_of_levels)�selfrrrrr	r	r�__init__-s"
zEmbeddedLevelGraph.__init__cCsd|j|j|jfS)Nz+EmbeddedLevelGraph(LG=%r,dmp=%r,dlevels=%r)�rrr�r%r	r	r�__repr__Is�zEmbeddedLevelGraph.__repr__cCsd|j|j|jfS)NzVEmbedded Level Graph consisting of %s with point dictionary %s and level dictionary %sr'r(r	r	r�__str__Ms��zEmbeddedLevelGraph.__str__c
s�dd�}dd�}td|j�|j�t����D]@}��|�}td|���|�D]}td|��|�f�qTq0tt	�fdd	�|j
D���}td
|t|���td�|j
D]6}td|j
|��|���
|�����|��f�q�td
|t�j����fdd��jD�}i}	|��D].\}
}||	v�r@|	|�|
�n
|
g|	|<�q|	D]h}td|t|	|��|d����|d��|d����|d��|�fdd�|	|D��f��qRdS)z=
        A more user-friendly display of __str__ :-)
        cSspt|�dkr`dg}|dd�D]}|�d|�q|�d|d�|�d|d�d�|�Sd	|d
SdS)N�zs �����z%r, z%r zand %r.������z %r.r)r!�append�join)�L�s�xr	r	r�_list_printVs
z/EmbeddedLevelGraph.explain.<locals>._list_printcSs|dkrdSd|SdS)Nr+zone edgez%r edgesr	��ir	r	r�_numasz(EmbeddedLevelGraph.explain.<locals>._numz)LevelGraph embedded into stratum %s with:zOn level %r:z"* A vertex (number %r) of genus %rc3s|]}����|��VqdS�N)�level_number�
levelofleg)r�leg�rr	r�	<genexpr>nrz-EmbeddedLevelGraph.explain.<locals>.<genexpr>z The marked points are on level%szMore precisely, we have:z6* Marked point %r of order %r on vertex %r on level %rz$Finally, we have %s. More precisely:cs*i|]"}|��|d���|d�f�qS�rr+)�vertex�r�er<r	rr{rz.EmbeddedLevelGraph.explain.<locals>.<dictcomp>zM* %s between vertex %r (on level %r) and vertex %r (on level %r) with prong%srr+csg|]}��|��qSr	)�prong)r�eer<r	r�
<listcomp>�rz.EmbeddedLevelGraph.explain.<locals>.<listcomp>N)�printrr�range�numberoflevels�internal_level_number�verticesonlevel�genus�listr"r�sorted�
orderatlegr?r9r:r!�edgesrr/�
levelofvertex)r%r4r7�l�
internal_l�vZ
levels_of_mpsr;�	edge_dictZ
edge_dict_inv�krAr	r<r�explainRsV
�
�
����
��zEmbeddedLevelGraph.explaincCs2t|t�sdS|j|jko0|j|jko0|j|jkS)NF)�
isinstancerrrr�r%�otherr	r	r�__eq__�s
zEmbeddedLevelGraph.__eq__cCs
|j��Sr8)r�is_bicr(r	r	rrZ�szEmbeddedLevelGraph.is_biccCs2|jdur,|��std��t|jj���|_|jS)z�
        If self is a BIC: the lcm of the prongs.

        Raises:
            RuntimeError: raised if self is not a BIC.

        Returns:
            int: lcm of the prongs.
        Nzell only defined for BICs!)rrZ�RuntimeErrorrr�prongs�valuesr(r	r	r�ell�s

zEmbeddedLevelGraph.ellc	Cs|jjdkrtd��|jjdj}d}|jj}|jjD]�}|jjdd�}|�|�|�	�}|D]}|�
|�q`|��|gks�J�t|���dkr�t
|���}|td|||�t|d|j�|��7}q6t|���dks�J�|t|d�t|d|j�|��7}q6|j|S)Nr+z)Cannot compute b on disconnected stratum.r���)r�_h0�
ValueError�	_sig_list�gr�stgraphrN�remove�copy�
contract_edger!�genera�minrrBr^)	r%re�valrfrArCZ
curr_graphZcontrr6r	r	r�b�s$
2*zEmbeddedLevelGraph.bcCs.|j|jj|jjt|jj�t|jj�Sr8)r^�bot�	kappa_EKZrr�Nr(r	r	r�c�s
�zEmbeddedLevelGraph.ccCs|jdur|��|jSr8)r�splitr(r	r	r�top�s
zEmbeddedLevelGraph.topcCs|jdur|��|jSr8)rrrr(r	r	rrn�s
zEmbeddedLevelGraph.botcCs|jdur|��|jSr8)rrrr(r	r	r�clutch_dict�s
zEmbeddedLevelGraph.clutch_dictcCs|jdur|��|jSr8)rrrr(r	r	r�emb_bot�s
zEmbeddedLevelGraph.emb_botcCs|jdur|��|jSr8)rrrr(r	r	r�emb_top�s
zEmbeddedLevelGraph.emb_topc
Cs�dd�|jjjdd�D�}|D]}|jj�|�qg}t|jj�D]X\}}|ddf}|D]@}d||j|f}|j�|j|�}	|�	|j�
|	�||f�qXqB|jj�|�dS)	aO
        We add the vertices at infinity to the underlying_graph of self.LG.

        These are given by the residue conditions.

        More precisely: Recall that the underlying_graph of self.LG has vertices
        and edges of self.LG stored in the form UG_vertex = (vertex number, genus, 'LG')
        and edges of the underlying graph are of the form: (UG_vertex, UG_vertex, edge name)
        We now add vertices 'at level infinity' by adding, for each res_cond of self.X

        * a UG_vertex called (i, 0, 'res') (where i is the index of the condition in res_cond
          we are currently considering) and edges so that each residue
          condition corresponds to an edge from the corresponding pole to some
          residue at 'level infinity'. We store these in the form:
        * (res_vertex, UG_vertex, resiedgej)
          Here UG_vertex is the vertex of self.LG, in the form (vertex number, genus, 'LG'),
          that res_vertex is attached to and j is the leg of that vertex (as a leg of self.LG!)
          corresponding to the pole that resi should be attached to.
        cSsg|]}|ddkr|�qS)r_�resr	�rrRr	r	rrD�s�z?EmbeddedLevelGraph.add_vertices_at_infinity.<locals>.<listcomp>T)�sortrrwzres%redge%rN)r�underlying_graph�vertices�
delete_vertex�	enumerater�res_condrr?r/�	UG_vertex�	add_edges)
r%Zexisting_residuesrRrNr6�rcZv_name�pZe_nameZ
v_on_graphr	r	rr�s
z+EmbeddedLevelGraph.add_vertices_at_infinityc	s�i�|jjD]F}|j�|j|�}z�|�|�WqtyP|g�|<Yq0qg}�D]"�|���fdd�|jjD��q\tt|�S)z�
        The matrix associated to the residue conditions imposed by the residue theorem
        on each vertex of self.

        Returns:
            SAGE Matrix: matrix of residue conditions given by RT
        csg|]}t|��v��qSr	��int�rr��Zpoles_by_vertexrRr	rrDs�z=EmbeddedLevelGraph.residue_matrix_from_RT.<locals>.<listcomp>)	r�	_polelistrr?rr/�KeyErrorrr)r%r�r?�rowsr	r�r�residue_matrix_from_RTs
�
z)EmbeddedLevelGraph.residue_matrix_from_RTcCs&|j��}|r|�|j�}n|j}|S)z�
        Residue matrix with GRC conditions and RT conditions (for each vertex).

        OUTPUT:

        A matrix with number of poles columns and a row for each condition.
        )r�residue_matrix�stackr�)r%�Mr	r	r�full_residue_matrixs


z&EmbeddedLevelGraph.full_residue_matrixcs`|jj�|���fdd�tt|jj��D�g}|j}|rX|�t|��}|��|j��kSdSdS)a,
        Check if the residue at pole is forced zero by residue conditions.

        NOTE: We DO include the RT on the vertices in this check!

        Args:
            pole (tuple): pole (as a point (i,j) of self.X)

        Returns:
            bool: True if forced zero, False otherwise.
        csg|]}t�|k��qSr	r��r�jr5r	rrD?rz3EmbeddedLevelGraph.residue_zero.<locals>.<listcomp>FN)	rr��indexrFr!r�r�r�rank)r%�pole�res_vecZRM�stackedr	r5r�residue_zero0s zEmbeddedLevelGraph.residue_zeroc	
s�z�j|}Wn�ty�t�fdd�t�jjdd�D��}�jj||d�}g|_t	�}|j
D]b}||vrnq`|j
|g}�jD],\}}|�|j
||�|�
||g�q�|j�tt	|���q`|�j|<Yn0|S)a�
        The generalised stratum on level l.

        Note that this is cached, i.e. on first call, it is stored in the dictionary
        _level.

        INPUT:

        l: integer
        The relative level number (0,...,codim)

        OUTPUT:

        The LevelStratum that is

        * a list of Signatures (one for each vertex on the level)
        * a list of residue conditions, i.e. a list [res_1,...,res_r]
          where each res_k is a list of tuples [(i_1,j_1),...,(i_n,j_n)]
          where each tuple (i,j) refers to the point j (i.e. index) on the
          component i and such that the residues at these points add up
          to 0.
        * a dictionary of legs, i.e. n -> (i,j) where n is the original
          number of the point (on the LevelGraph self) and i is the
          number of the component, j the index of the point in the signature tuple.

        Note that LevelStratum is a GeneralisedStratum together with
        a leg dictionary. Here, we provide an additional attribute:

        * leg_orbits, a nested list giving the orbits of the points on the level
          under the automorphism group of self.
        c3s|]}�j|VqdSr8�rr�r(r	rr=srz+EmbeddedLevelGraph.level.<locals>.<genexpr>r+��	max_level)�excluded_poles)rr��tuplerrr~r�stratum_from_level�
leg_orbitsr"�	_leg_dict�
automorphismsr/�updaterK)	r%rPZLSr��seenr;Z
curr_orbitZ_v_map�l_mapr	r(r�levelIs& �
zEmbeddedLevelGraph.levelcCs�|j�|j�|��}|j�|j�|��}||kr4dS||ks@J�|�|�j|}|�|�j|}|�|�jD]}||vrl||vSqltd||�|�j|�|�f��dS)ab
        Check if leg and other_leg are in the same Aut-orbit of self.

        Args:
            leg (int): leg on self.LG
            other_leg (int): leg on self.LG

        Raises:
            RuntimeError: If leg is not in any aut-orbit of the level it should be on.

        Returns:
            bool: True if they are in the same orbit of self.level(levelofleg),
                    False, otherwise.

        EXAMPLES::

            Note the asymmetric banana graph.

            The symmetric one has isomorphisms.

            Legs are isomorphic to themselves.

            It's symmetric.

        Fz leg %r not in any orbit %r of %rN)rr9r:r�r�r�r[)r%r;Z	other_legr�Zother_levelZemb_legZ
emb_other_leg�orbitr	r	r�legs_are_isomorphic�s��z&EmbeddedLevelGraph.legs_are_isomorphiccCs\||jjvrtd||f��t|g�}|jD]*\}}||d||df}|�|�q,|S)ai
        The edge orbit of edge in self.

        raises a ValueError if edge is not an edge of self.LG

        INPUT:

        edge: tuple
        An edge of ``self.LG``, i.e. tuple (start leg, end leg), where start
        leg should not be on a lower level than end leg.

        OUTPUT:

        The set of edges in automorphism orbit of ``edge``.
        z%r is not an edge of %r!rr+)rrNrcr"r��add)r%�edger2�v_mapr�Znew_edger	r	r�
edge_orbit�s
zEmbeddedLevelGraph.edge_orbitcCst|�|��S)a�
        Length of the edge orbit of edge in self.

        Args:
            edge (tuple): edge of self.LG, i.e. tuple (start leg, end leg), where
                start leg should not be on a lower level than end leg.

        Raises:
            ValueError: if edge is not an edge of self.LG

        Returns:
            int: length of the aut-orbit of edge.

        EXAMPLES::


            Prongs influence the orbit length.

        )r!r�)r%r�r	r	r�len_edge_orbit�sz!EmbeddedLevelGraph.len_edge_orbitcCs<g}|jD],\}}|D]}|||krq
q|�|�q
|Sr8)r�r/)r%Z	leg_tuple�stabsr�r�rPr	r	r�automorphisms_stabilising_legs�sz1EmbeddedLevelGraph.automorphisms_stabilising_legscs>|jj|dd��|j��}�fdd��jD�}t|j�||�S)a�
        Squish all levels except for i.

        Note that delta(1) contracts everything except top-level and that the
        argument is interpreted via internal_level_number (i.e. a relative level number).

        Moreover, dlevels is set to map to 0 and -1(!).

        Args:
            i (int): Level not to be squished.

        Returns:
            EmbeddedLevelGraph: Embedded BIC (result of applying delta to the
                underlying LevelGraph)
        T��quietcsi|]}|��|��qSr	�r9�rrP��newLGr	rr�rz,EmbeddedLevelGraph.delta.<locals>.<dictcomp>)r�deltarrh�levelsrr)r%r6�newdmp�
newdlevelsr	r�rr��s
zEmbeddedLevelGraph.deltacsF|jj|j�|�dd��|j��}�fdd��jD�}t|j�||�S)a'
        Squish level crossing below level 'level'.

        Note that in contrast to the levelgraph method, we work with relative
        level numbers here!

        Args:
            level (int): relative (!) level number.

        Returns:
            EmbeddedLevelGraph: Result of squishing.

        EXAMPLES::

            sage: from admcycles.diffstrata import *
            sage: X=GeneralisedStratum([Signature((4,))])
            sage: p = X.enhanced_profiles_of_length(4)[0][0]
            sage: g = X.lookup_graph(p)

            lookup_graph uses the sorted profile (note that these do not have to be reduced!):

            sage: assert any(g.squish_vertical(0).is_isomorphic(G) for G in X.lookup(p[1:]))
            sage: assert any(g.squish_vertical(1).is_isomorphic(G) for G in X.lookup(p[:1]+p[2:]))
            sage: assert any(g.squish_vertical(2).is_isomorphic(G) for G in X.lookup(p[:2]+p[3:]))
            sage: assert any(g.squish_vertical(3).is_isomorphic(G) for G in X.lookup(p[:3]))

            Squishing outside the range of levels does nothing:

            sage: assert g.squish_vertical(4) == g

            Recursive squishing removes larger parts of the profile:

            sage: assert any(g.squish_vertical(3).squish_vertical(2).is_isomorphic(G) for G in X.lookup(p[:2]))
        Tr�csi|]}|��|��qSr	r�r�r�r	rr$rz6EmbeddedLevelGraph.squish_vertical.<locals>.<dictcomp>)r�squish_verticalrHrrhr�rr)r%r�r�r�r	r�rr��s#�
z"EmbeddedLevelGraph.squish_verticalcs����std�����d��_��d��_�fdd�t�j�D��_�fdd�t�j�D��_�fdd��j	j
D��_�j�j�j�j�j�jd�S)	a�
        Splits embedded BIC self into top and bottom component.

        Raises a ValueError if self is not a BIC.

        OUTPUT:

        A dictionary consising of

        * the GeneralisedStratum self.X
        * the top component LevelStratum
        * the bottom component LevelStratum
        * the clutching dictionary mapping ex-half-edges on
          top to their partners on bottom (both as points in the
          respective strata!)
        * a dictionary embedding top into the stratum of self
        * a dictionary embedding bot into the stratum of self

        Note that clutch_dict, emb_top and emb_bot are dictionaries between
        points of strata, i.e. after applying dmp to the points!
        zFError: %s is not a BIC! Cannot be split into Top and Bottom component!rr+cs8i|]0}�j��j�|��dkr�j�|��j|�qS�r)rr9r:r�stratum_numberrr�r(r	rrNs�z,EmbeddedLevelGraph.split.<locals>.<dictcomp>cs8i|]0}�j��j�|��dkr�j�|��j|�qS)r+)rr9r:rr�rr�r(r	rrQs�cs*i|]"}�j�|d��j�|d��qSr>)rr�rr@r(r	rrZs���)rrs�bottomrt�emb_dict_top�emb_dict_bot)
rZrcr�rr�iterrrrrrNrrr(r	r(rrr's*��
�
�	
��zEmbeddedLevelGraph.splitcsdt�j���r.t�fdd�t�j�D��r.dSt�jjdd�}t�fdd�|D��}�j	j
|dd�S)	z`
        Check the R-GRC for self.

        Returns:
            bool: result of R-GRC.
        c3s|]}��|���VqdSr8)r��is_emptyr�r(r	rr=ms�z.EmbeddedLevelGraph.is_legal.<locals>.<genexpr>Fr+r�c3s|]}�j|VqdSr8r�r�r(r	rr=trT)r�r�)rKr�simple_poles�anyrFr$rr~r�r�is_legal)r%Zpoles_in_rc_stratumZpoles_in_rc_graphr	r(rr�bs
�zEmbeddedLevelGraph.is_legalcs�dd�t|jj�D��|jD]}�|dd7<qdg�fdd�td|jj�D�}i}d}tdt|jj�d�D]R}||jvr�|j|d||j|dd||<qvt|j�|||<|d}qv|S)a
        Construct a dictionary for relabelling the markings. A standard labelling will label the legs
        of markings first and then the half edges. If the generalised stratum has only one component,
        the standard label of a marking will be exactly the position of that marking in the signature.

        EXAMPLES::

            sage: from admcycles.diffstrata.generalisedstratum import Stratum
            sage: X=Stratum((1,1))
            sage: X.bics[0]
            EmbeddedLevelGraph(LG=LevelGraph([1, 0],[[1, 2], [3, 4, 5, 6]],[(1, 5), (2, 6)],{1: 0, 2: 0, 3: 1, 4: 1, 5: -2, 6: -2},[0, -1],True),dmp={3: (0, 0), 4: (0, 1)},dlevels={0: 0, -1: -1})
            sage: X.bics[0].standard_markings()
            {1: 3, 2: 4, 3: 1, 4: 2, 5: 5, 6: 6}

        cSsg|]}d�qSr�r	�rr6r	r	rrD�rz8EmbeddedLevelGraph.standard_markings.<locals>.<listcomp>rr+cs&g|]}t�fdd�t|�D���qS)c3s|]}�|VqdSr8r	r���n_listr	rr=�rzBEmbeddedLevelGraph.standard_markings.<locals>.<listcomp>.<genexpr>)�sumrFr�r�r	rrD�s�)rFrrbrr!r�
poleordersr)r%�tZn_sums�new_leg_dict�hr6r	r�r�standard_markingsws$
�
��

z$EmbeddedLevelGraph.standard_markingsTcsV|j��|�}�fdd�|j��D�}|r@dd�t|���D�}t|j|||j�}|S)az
        Relabel the EmbeddedLevelGraph by a given dictionary.

        INPUT:

            - legdict (dict): A dictionary indicating the map from old markings
              to the new ones

        EXAMPLES::
            sage: from admcycles.diffstrata.generalisedstratum import Stratum
            sage: X = Stratum((1,1))
            sage: dict1={1: 3, 2: 4, 3: 1, 4: 2, 5: 5, 6: 6}
            sage: X.bics[0].relabel(dict1)
            EmbeddedLevelGraph(LG=LevelGraph([1, 0],[[3, 4], [1, 2, 5, 6]],[(3, 5), (4, 6)],{1: 1, 2: 1, 3: 0, 4: 0, 5: -2, 6: -2},[0, -1],True),dmp={1: (0, 0), 2: (0, 1)},dlevels={0: 0, -1: -1})

        csi|]\}}�||�qSr	r	)rr6r���legdictr	rr�rz.EmbeddedLevelGraph.relabel.<locals>.<dictcomp>cSsi|]\}}||�qSr	r	)r�armr	r	rr�r)r�relabelrrrLrrr)r%r��tidyupr��new_dmpZnewEmbLGr	r�rr��szEmbeddedLevelGraph.relabelcCs<t|t�sdSzt|�|��WdSty6YdS0dS)z�
        Check if self and other are isomorphic (as EmbeddedLevelGraphs).

        Args:
            other (EmbeddedLevelGraph): Graph to check isomorphism.

        Returns:
            bool: True if there exists at least one isomorphism.
        FTN)rVr�next�isomorphisms�
StopIterationrWr	r	r�
is_isomorphic�s
z EmbeddedLevelGraph.is_isomorphiccCs|jst|�|��|_|jS)a-
        The automorphisms of self (as automorphisms of the underlying LevelGraph,
        respecting the embedding, see doc of isomorphisms).

        OUTPUT:

        A list of pairs ``(map_of_vertices, map_of_legs)``. Both ``maps_of_vertices``
        and ``map_of_legs`` are dictionaries.
        )rrKr�r(r	r	rr��sz EmbeddedLevelGraph.automorphismsc#s�i}i}tj��fdd��j��D��D]j}|D]\}}|�|�|�|�q0�jjD](}||d||df�jjvrVq(qV|��|��fVq(dS)a�
        Generator yielding the "next" isomorphism of self and other.

        Note that while this gives an "isomorphism" from self.LG to other.LG, this
        is not necessarily an isomorphism of the LevelGraphs (the numbered points may
        be permuted if this is "fixed" by the embedding).

        INPUT:

        other: EmbeddedLevelGraph
        The (potentially) isomorphic EmbeddedLevelGraph.

        OUTPUT:

        An iterator going through isomorphisms. Each isomorphism is encoded by a
        pair of dictionaries ``(vertex_map, leg_map)`` The dictionaries
        ``vertex_map`` (respectively ``leg_map``) is to the mapping of the
        vertices (resp. legs) of ``self.LG`` to the vertices (resp. legs) of
        ``other.LG``.
        csg|]}���|��qSr	)�
_level_isor��rXr%r	rrD�rz3EmbeddedLevelGraph.isomorphisms.<locals>.<listcomp>rr+N)�	itertools�productrr]r�rrNrh)r%rXZ
isom_vertices�	isom_legsZ
level_isosZlevel_iso_vZlevel_iso_lrAr	r�rr��s�
 zEmbeddedLevelGraph.isomorphismsc	#s6�
j�|�}�	j�|�}�
j�|��
�	j�|��t�
�t��krDdS�
fdd��
D�}�	fdd��D�}�
fdd��
D���	fdd��D��dd�t��D�}d	d�t��D�}t|�t|�kr�dS�
fd
d��D���	fdd��D��i}	i}
i}t|�D]:\}}
z||
�|�Wq�t�y4|g||
<Yq�0q�i}t|�D]<\}}
z||
�|�Wnt�y||g||
<Yn0�qDdd��D�}d
d��D�}t|�t|�k�r�dS�
j�	�D�]F\}}�	j
|}||v�s�||v�s�q�||v�r�||v�s||v�r||v�rdS||}||}||||k�sft�|�t�|�k�sf�|�|k�rldSz|	||k�r�WdSWnXt�y�||}
|||
v�r�||	|<||
�|�||
�|�nYdSYn0||
|<||�|�||�|��q�i�g��������fdd��i�g�����	�
fdd��g}|D].}
g��||
||
�|��dd���qLtj
|�D]�}|D]}|	�|��q���
fdd�|	�	�D�}g}|	D]2}g��||||	|�|��dd���q�tj
|�D].}|D]}|
�|��q|��|
��fV�q��q�dS)a>
        Generator yielding the "next" isomorphism of level l of self and other.

        Here, l is a value of dlevels (this should be compatible).

        Note that we require the graph to have no horizontal edges, i.e. the level
        contains no edges!

        TODO: * Maybe add future horizontal support?
              * Maybe use relative level number instead? (this seems to give weird behaviour
                right now...)

        Args:
            other (EmbeddedLevelGraph): The embedded graph we are checking for isomorphism.
            l (int): Level number (embedded into the stratum, i.e. value of dlevels).

        Yields:
            tuple: the next isomorphism of levels:
                dict: vertices of self.LG -> vertices of other.LG
                dict: legs of self.LG -> legs of other.LG
        Ncsg|]}�j�|��qSr	�rrJr�r(r	rrD,rz1EmbeddedLevelGraph._level_iso.<locals>.<listcomp>csg|]}�j�|��qSr	r�r��rXr	rrD-rcsg|]}�j�|��qSr	�r�legsatvertexrxr(r	rrD/rcsg|]}�j�|��qSr	r�rxr�r	rrD0rcSs i|]\}}|D]
}||�qqSr	r	�rr6�legsrPr	r	rr2s�z1EmbeddedLevelGraph._level_iso.<locals>.<dictcomp>cSs i|]\}}|D]
}||�qqSr	r	r�r	r	rr4s�cs"g|]}t�fdd�|D���qS)csg|]}�j�|��qSr	�rrMr�r(r	rrD9r�<EmbeddedLevelGraph._level_iso.<locals>.<listcomp>.<listcomp>�rL�rr�r(r	rrD9s�cs"g|]}t�fdd�|D���qS)csg|]}�j�|��qSr	r�r�r�r	rrD;rr�r�r�r�r	rrD;s�cSsg|]}|dd��qSr8r	r�r	r	rrDRrcSsg|]}|dd��qSr8r	r�r	r	rrDSrcs�|s,tdd�|D��sJ�������dS|��}t�|�}t|�D]\\}}|durZqH|t�|�ksH�|�|kr|qHd||<|�|<�||��|=|||<qH|�|�dS)Ncss|]}|duVqdSr8r	)r�tvr	r	rr=�rzEEmbeddedLevelGraph._level_iso.<locals>.vertex_maps.<locals>.<genexpr>)�allr/rh�popr!r})�sl�tlZcurr_vZ	curr_legsr6r�)�
curr_v_map�legal_v_maps�
legs_other�	legs_self�order_sorted_other�order_sorted_self�vertex_mapsr	rr��s&�

z2EmbeddedLevelGraph._level_iso.<locals>.vertex_mapscs�|s,tdd�|D��sJ�������dS|��}t|�D]R\}}|durNq<�j�|��j�|�kr<d||<|�|<�||��|=|||<q<|�|�dS)Ncss|]}|duVqdSr8r	)r�tlegr	r	rr=�rzBEmbeddedLevelGraph._level_iso.<locals>.leg_maps.<locals>.<genexpr>)r�r/rhr�r}rrM)r�r�Zcurr_lr6r�)�
curr_l_map�leg_maps�legal_l_mapsrXr%r	rr��s

z/EmbeddedLevelGraph._level_iso.<locals>.leg_mapscsi|]\}}�|�|�qSr	r	)rrTrR)�vv_other_idx�vv_self_idxr	rr�s�)rrHrIr!r}r/r�rLrrrrgr�r�r�rh)r%rXrPZl_selfZl_otherZvv_selfZvv_otherZ
leg_dict_selfZleg_dict_otherZ	isom_vertr��sourcer6re�targetZlegs_sourceZlegs_target�p_selfr�Zp_otherZv_selfZv_otherZv_isom_listZv_mapsr�Zreturn_isom_vertZl_isom_listrRZl_mapsr�r	)r�r�r�r�r�r�r�r�r�rXr%r�r�r�rr�s�#��
�
�
�����zEmbeddedLevelGraph._level_isoN)T)'�__name__�
__module__�__qualname__�__doc__r&r)r*rUrYrrZ�propertyr^rmrqrsrnrtrurvrr�r�r�r�r�r�r�r�r�r�rrr�r�r�r�r�r�r�r	r	r	rrsb 8








$<)

*;#

+r)r��sage.structure.sage_objectr�sage.matrix.constructorr�sage.misc.flattenr�sage.misc.cachefuncr�sage.rings.rational_fieldr�sage.arith.functionsrrr	r	r	r�<module>s