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

��c���@s�ddlmZddlmZddlmZddlmZddlm	Z	ddl
mZddlm
Z
ddlmZdd	lmZdd
lmZddlmZGdd
�d
e�ZdS)�)�deepcopy)�
SageObject)�ZZ)�flatten)�sign)�
cached_method)�Graph)�text)�	GraphIsom)�StableGraph)�
kSignaturec@s�eZdZdZ	d�dd�Ze	d�dd��Zdd�Zd	d
�Zdd�Z	d
d�Z
dd�Zedd��Z
edd��Zed�dd��Zedd��Zedd��Zedd��Zedd��Zed d!��Zed"d#��Zed$d%��Zed&d'��Zed(d)��Zed*d+��Zed,d-��Zed.d/��Zed�d0d1��Zed2d3��Zd4d5�Zed6d7��Z ed8d9��Z!ed:d;��Z"ed<d=��Z#ed>d?��Z$ed@dA��Z%edBdC��Z&edDdE��Z'edFdG��Z(ed�dHdI��Z)edJdK��Z*edLdM��Z+edNdO��Z,edPdQ��Z-edRdS��Z.edTdU��Z/ed�dVdW��Z0ed�dXdY��Z1ed�dZd[��Z2ed�d\d]��Z3d^d_�Z4d`da�Z5dbdc�Z6ddde�Z7dfdg�Z8dhdi�Z9djdk�Z:dldm�Z;dndo�Z<d�dpdq�Z=d�dsdt�Z>d�dudv�Z?d�dwdx�Z@dydz�ZAd{d|�ZBd}d~�ZCdd��ZDd�d��ZEd�d�d��ZFd�d��ZGdS)��KLevelGrapha�
    Create a (stable) level graph for a k-differential.

    .. NOTE::

        This is a low-level class and should NEVER be invoked directly!
        Preferably, ``EmbeddedLevelGraphs`` should be used and these should be
        generated automatically by ``Stratum`` (or ``GeneralisedStratum``).

    .. NOTE::

        We do not inherit from stgraph/StableGraph anymore, as KLevelGraphs
        should be static objects!

    Extends admcycles stgraph to represent a level graph as a stgraph,
    i.e. a list of genera, a list of legs and a list of edges, plus a list of
    poleorders for each leg and a list of levels for each vertex.

    Note that the class will warn if the data is not admissible, i.e. if the
    graph is not stable or the pole orders at separating nodes across levels do
    not add up to -2 or -1 on the same level (unless this is suppressed with
    quiet=True).

    INPUT:

    genera : list
    List of genera of the vertices of length m.

    legs : list
    List of length m, where ith entry is list of legs attached to vertex i.
    By convention, legs are unique positive integers.

    edges : list
    List of edges of the graph. Each edge is a 2-tuple of legs.

    poleorders : dictionary
    Dictionary of the form leg number : poleorder

    levels : list
    List of length m, where the ith entry corresponds to the level of
    vertex i.
    By convention, top level is 0 and levels go down by 1, in particular
    they are NEGATIVE numbers!

    k : int
    The order of the differential.

    quiet : optional boolean (default = False)
    Suppresses most error messages.

    ALTERNATIVELY, the pole orders can be supplied as a list by calling
    KLevelGraph.fromPOlist:
    poleorders : list
    List of order of the zero (+) or pole (-) at each leg. The ith element
    of the list corresponds to the order at the leg with the marking i+1
    (because lists start at 0 and the legs are positive integers).

    EXAMPLES:

    Creating a level graph with three components on different levels of genus 1,
    3 and 0. The bottom level has a horizontal node.::

        sage: from admcycles.diffstrata.klevelgraph import KLevelGraph
        sage: G = KLevelGraph.fromPOlist([1,3,0],[[1,2],[3,4,5],[6,7,8,9]],[(2,3),(5,6),(7,8)],[2,-2,0,6,-2,0,-1,-1,0],[-2,-1,0],1); G  #  doctest: +SKIP
        KLevelGraph([1, 3, 0],[[1, 2], [3, 4, 5], [6, 7, 8, 9]],[(3, 2), (6, 5), (7, 8)],{1: 2, 2: -2, 3: 0, 4: 6, 5: -2, 6: 0, 7: -1, 8: -1, 9: 0},[-2, -1, 0],1,True)

    or alternatively::

        sage: KLevelGraph([1, 3, 0],[[1, 2], [3, 4, 5], [6, 7, 8, 9]],[(3, 2), (6, 5), (7, 8)],{1: 2, 2: -2, 3: 0, 4: 6, 5: -2, 6: 0, 7: -1, 8: -1, 9: 0},[-2, -1, 0],1,quiet=True)
        KLevelGraph([1, 3, 0],[[1, 2], [3, 4, 5], [6, 7, 8, 9]],[(3, 2), (6, 5), (7, 8)],{1: 2, 2: -2, 3: 0, 4: 6, 5: -2, 6: 0, 7: -1, 8: -1, 9: 0},[-2, -1, 0],1,True)

    Creating a level graph with two components on different levels of genus 1 and 1 and a quadratic differential.::

        sage: KLevelGraph.fromPOlist([1,1],[[1],[2,3]],[(1,2)],[0,-4,4],[0,-1],2)
        KLevelGraph([1, 1],[[1], [2, 3]],[(1, 2)],{1: 0, 2: -4, 3: 4},[0, -1],2,True)

    We get a warning if the graph has non-stable components: (not any more ;-))::

        sage: G = KLevelGraph.fromPOlist([1,3,0,0],[[1,2],[3,4,5],[6,7,8,9],[10]],[(2,3),(5,6),(7,8),(9,10)],[2,-2,0,6,-2,0,-1,-1,0,-2],[-3,-2,0,-1],1); G  # doctest: +SKIP
        Warning: Component 3 is not stable: g = 0 but only 1 leg(s)!
        Warning: Graph not stable!
        KLevelGraph([1, 3, 0, 0],[[1, 2], [3, 4, 5], [6, 7, 8, 9], [10]],[(3, 2), (6, 5), (7, 8), (9, 10)],{1: 2, 2: -2, 3: 0, 4: 6, 5: -2, 6: 0, 7: -1, 8: -1, 9: 0, 10: -2},[-3, -2, 0, -1],1,True)
    Fc
s�d}t|�t|�krtd��||_||_||_�|_||_t�fdd�|��D��}	t	|	|�|_
d|_|��|r>|�
|�d|_i|_d|_dS)NFz)genera and legs must have the same lengthc3s�|]}�|VqdS�N���.0�l��
poleordersr�D/home/user/Introduction lectures/admcycles/diffstrata/klevelgraph.py�	<genexpr>ps�z'KLevelGraph.__init__.<locals>.<genexpr>)�len�
ValueError�genera�legs�edgesr�levels�tuple�
list_markingsr�sig�_stgraph�
_init_more�checkadmissible�_has_long_edge�_is_long�_is_bic)
�selfrrrrr�k�quiet�checks�sig_listrrr�__init__es"

zKLevelGraph.__init__c	sptt|���t��t��kr tdtt���dtt�������fdd�tt���D�}||||||||�S)zz
        This gives a KLevelGraph where the poleorders are given as a list, not
        directly as a dictionary.
        z4Numbers of legs and pole orders do not agree! Legs: z Pole orders: csi|]	}�|�|�qSrr�r�i��poleordersaslist�
sortedlegsrr�
<dictcomp>���z*KLevelGraph.fromPOlist.<locals>.<dictcomp>)�sortedrrr�repr�range)	�clsrrrr/rr'r(�
poleorderdictrr.r�
fromPOlist{s
��
�
�zKLevelGraph.fromPOlistcCsd|��dS)NzKLevelGraph(�))�input_as_string�r&rrr�__repr__�szKLevelGraph.__repr__cCstt|��Sr)�hashr4r;rrr�__hash__�szKLevelGraph.__hash__cCsTdt|j�dt|j�dt|j�dt|j�dt|j�dt|j�S)NzKLevelGraph � )r4rrrrrr'r;rrr�__str__�sH��������	�
���
������zKLevelGraph.__str__cCsVt|j�dt|j�dt|j�dt|j�dt|j�dt|jj�dS)zX
        return a string that can be given as argument to __init__ to give self
        �,z,True)r4rrrrrrr'r;rrrr:�s"������
��zKLevelGraph.input_as_stringcCsbt|t�sdS|j|jko0|j|jko0|j|jko0t|j�t|j�ko0|j|jko0|jj	|jj	kS)NF)
�
isinstancer
rrr�setrrrr')r&�otherrrr�__eq__�s(

�
�
�����
��zKLevelGraph.__eq__cCsHt|j�t|j�t|j�t��}||jjks"Jd|j|f��|S)NzSignature %r does not match %r!)�sumrrrr�oner�g)r&�genusrrrrH�s���z
KLevelGraph.gcCs8|jdurtdd�|jD�dd�|jD�|j�|_|jS)NcS�g|]}t|��qSr��int)rrHrrr�
<listcomp>��z'KLevelGraph.stgraph.<locals>.<listcomp>cSsg|]	}dd�|D��qS)cSrJrrKrrrrrM�rNz2KLevelGraph.stgraph.<locals>.<listcomp>.<listcomp>r)r�leg_listrrrrM�r2)r �stgraphrrrr;rrrrP�s
��zKLevelGraph.stgraphNcsV|durt�fdd�tt�j��D��St�j|�}�jD]}|t|�8}qt|�S)zR
        Return the list of markings (non-edge legs) of self at vertex v.
        Ncs g|]}��|�D]}|�q	qSr)r)r�v�jr;rrrM�s
�
�z-KLevelGraph.list_markings.<locals>.<listcomp>)rr5rrrCrr)r&rQ�s�err;rr�s 
zKLevelGraph.list_markingscC�
|j|S)z�
        The vertex (as index of genera) where leg is located.

        Args:
            leg (int): leg

        Returns:
            int: index of genera
        )�legdict�r&�legrrr�vertex)s
zKLevelGraph.vertexcCsttt|j���Sr��listr5rrr;rrr�vertex_list6szKLevelGraph.vertex_listcCs|jSr�rr;rrr�
edges_list:szKLevelGraph.edges_listcCrUr�r�r&rQrrr�
levelofvertex>�
zKLevelGraph.levelofvertexcCs|�|�|��Sr)rarYrWrrr�
leveloflegBszKLevelGraph.leveloflegcCrUrrrWrrr�
orderatlegFrbzKLevelGraph.orderatlegc��fdd���|�D�S)Nc�g|]}��|��qSr�rd�rrXr;rrrML�z.KLevelGraph.ordersonvertex.<locals>.<listcomp>��legsatvertexr`rr;r�ordersonvertexJ�zKLevelGraph.ordersonvertexcs��fdd�tt�j��D�S)Nc�g|]}��|��kr|�qSr�ra�rrQ��levelr&rrrMP�
�z/KLevelGraph.verticesonlevel.<locals>.<listcomp>)r5rr�r&rrrrqr�verticesonlevelNszKLevelGraph.verticesonlevelcs��fdd��jD�S)Ncs4g|]}��|d��ks��|d��kr|�qS�r��rY�rrTr`rrrMU�
�z-KLevelGraph.edgesatvertex.<locals>.<listcomp>r]r`rr`r�
edgesatvertexSszKLevelGraph.edgesatvertexcCrUr�rr`rrrrkXrbzKLevelGraph.legsatvertexcst�fdd�|jD��S)z:
        Check if leg has an edge attached to it.
        c3s(�|]}|d�kp|d�kVqdS�rrwNrry�rXrrras�&z*KLevelGraph.is_halfedge.<locals>.<genexpr>)�anyrrWrr~r�is_halfedge\szKLevelGraph.is_halfedgecre)Ncsg|]}��|�dkr|�qS)�����rgrr;rrrMesz3KLevelGraph.simplepolesatvertex.<locals>.<listcomp>rjr`rr;r�simplepolesatvertexcrmzKLevelGraph.simplepolesatvertexcCs|dur|��S|j|S)zp
        Return the genus of vertex v.

        If v is None, return genus of the complete KLevelGraph.
        N)rHrr`rrrrIgs
zKLevelGraph.genuscCstt|j��Sr)rrCrr;rrr�numberoflevelssszKLevelGraph.numberoflevelscCs(|jdur|��dko|��|_|jS)N�)r%r��
is_horizontalr;rrr�is_bicws
zKLevelGraph.is_biccs$���dt�fdd��jD��S)zN
        Return the codim = No. of levels of self + horizontal edges.
        rwc3s�|]
}��|�rdVqdS)rwN�r�ryr;rrr�s�z$KLevelGraph.codim.<locals>.<genexpr>)r�rFrr;rr;r�codim|s
�zKLevelGraph.codimc���fdd��jD�S)zG
        Return list of edges with at least one node at level.
        cs4g|]}��|d��ks��|d��kr|�qSrv�rcryrqrrrM�rzz,KLevelGraph.edgesatlevel.<locals>.<listcomp>r]rtrrqr�edgesatlevel��zKLevelGraph.edgesatlevelcre)Ncsg|]	}��|�r|�qSrr�ryr;rrrM��z6KLevelGraph.horizontaledgesatlevel.<locals>.<listcomp>)r�rtrr;r�horizontaledgesatlevel�rmz"KLevelGraph.horizontaledgesatlevelcCs@z
|j�|�d}Wn
tyYdSw|dkrdS|j|S)a�
        Return the next lower level number or  False if no legal level
        (e.g. lowest level) is given as input.

        Point of discussion: Is it better to tidy up the level numbers
        to be directly ascending or not?

        Pro tidy: * this becomes obsolete ;)
                  * easier to check isomorphisms?
        Con tidy: * we "see" where we came from
                  * easier to undo/glue back in after cutting
        rwFr�)�sortedlevels�indexr)r&rZllindexrrr�nextlowerlevel�s�
zKLevelGraph.nextlowerlevelcCs:ttttt|j�����}t|�}|t|�krdS||S)a7
        Return the internal i-th level, e.g.

        self.levels = [0,-2,-5,-3]

        then

        internal_level_number(0) is 0
        internal_level_number(1) is -2
        internal_level_number(2) is -3
        internal_level_number(3) is -4

        Returns None if the level does not exist.
        N)r[�reversedr3rCr�absr)r&r-�reference_levelsrrr�internal_level_number�s
z!KLevelGraph.internal_level_numbercCs<ttttt|j�����}z|�|�WStyYdSw)a&
        Return the relative level number (positive!) of l, e.g.

        self.levels = [0,-2,-5,-3]

        then

        level_number(0) is 0
        level_number(-2) is 1
        level_number(-3) is 2
        level_number(-5) is 3

        Returns None if the level does not exist.
        N)r[r�r3rCrr�r)r&rr�rrr�level_number�s�zKLevelGraph.level_numbercCs^z|j|WSty.t|�|�|d��|�|�|d���dk}||j|<|YSw)zS
        Check if edge e is long, i.e. passes through more than one level.
        rrw)r$�KeyErrorr�r�rc)r&rT�ilrrr�is_long�s
���
�zKLevelGraph.is_longcCs:|jdur|jD]}|�|�rd|_|jSqd|_|jS)NTF)r#rr��r&rTrrr�
has_long_edge�s


�zKLevelGraph.has_long_edgecCs
|jdS)Nr)r�r;rrr�lowest_level�rbzKLevelGraph.lowest_levelcs^|durt�fdd��jD��S|�jvr!tdt|�d�dS��|d���|d�kS)	zX
        Check if edge e is a horizontal edge or if self has a horizontal edge.
        Nc3s�|]}��|�VqdSrr�ryr;rrr�s�z,KLevelGraph.is_horizontal.<locals>.<genexpr>�	Warning: z is not an edge of this graph!Frrw)rr�printr4rcr�rr;rr��s
zKLevelGraph.is_horizontalcst�fdd���|�D��S)z/
        Check if vertex v has a loop.
        c3s,�|]}��|d���|d�kVqdSr}rxryr;rrrs�$�z'KLevelGraph.has_loop.<locals>.<genexpr>)rr{r`rr;r�has_loop�s�zKLevelGraph.has_loopcr�)zy
        Return the edges going up from level l.

        This uses that e[0] is not on a lower level than e[1]!
        c�,g|]}��|d��kr��|�s|�qS�rw�rcr�ry�rr&rrrMs
�z5KLevelGraph.edgesgoingupfromlevel.<locals>.<listcomp>r]�r&rrr�r�edgesgoingupfromlevelsz!KLevelGraph.edgesgoingupfromlevelcs8�dur
ttt�j���S��fdd�tt�j��D�S)zh
        Return list of all vertices above level l.

        If l is None, return all vertices.
        Ncsg|]}��|��kr|�qSrrorpr�rrrMrsz-KLevelGraph.verticesabove.<locals>.<listcomp>rZr�rr�r�
verticesaboveszKLevelGraph.verticesabovecr�)zm
        Return a list of all edges above level l, i.e. start and end vertex
        have level > l.
        cs4g|]}��|d��kr��|d��kr|�qSrvr�ryr�rrrM s
�
�z*KLevelGraph.edgesabove.<locals>.<listcomp>r]r�rr�r�
edgesaboveszKLevelGraph.edgesabovecCs$|�|d�|ko|�|d�|kS)zL
        Check if e crosses level l (i.e. starts > l and ends <= l)
        rrwr�)r&rTrrrr�crosseslevel#s$zKLevelGraph.crosseslevelcr�)zS
        Return list of edges that go from above level l to below level l.
        cs<g|]}��|d��kr��|d�krnn|�qSrvr�ryr�rrrM/s
��z3KLevelGraph.edgesgoingpastlevel.<locals>.<listcomp>r]r�rr�r�edgesgoingpastlevel*r�zKLevelGraph.edgesgoingpastlevelcCsVd}|�|�s|s
td�d}|�|�s|std�d}|�|�s)|s'td�d}|S)a
        Run all kinds of checks on the level graph. Currently:
         * Check if orders on each komponent add up to k*(2g-2)
         * Check if graph is stable
         * Check if orders at edges sum to -k*2
         * Check if orders respect level crossing
        TzWarning: Illegal orders!FzWarning: Graph not stable!z"Warning: Illegal orders at a node!)�checkordersr��	is_stable�checkedgeorders)r&r(�
admissiblerrrr"8s	


zKLevelGraph.checkadmissiblecCsvt|j�D]3\}}t|�|��|jjd|dkr8|s5tdt|�dtt|�|���dt|��dSqdS)zK
        Check if the orders add up to k*(2g-2) on each component.
        r��Warning: Component z orders add up to z but component is of genus FT)�	enumeraterrFrlrr'r�r4)r&r(rQrHrrrr�Ps""������	zKLevelGraph.checkorderscCs�d|��dt|j�}|dkr|stdt|��dStt|j��D]7}d|�|�dt|�|��dkr[|sXtdt|�dt|�|��dtt|�|���d	�dSq$d
S)z+
        Check if graph is stable.
        r�rz*Warning: Total graph not stable! 2g-2+n = F�r�z is not stable: g = z
 but only z leg(s)!T)rIr�leglistr�r4r5rrk)r&r(rTrQrrrr�as0$�������
zKLevelGraph.is_stablec
Cs|jD]|}|�|d�|�|d�}||jjdkr1|s.tdt|�dt|�d�dSt|�|d�|�|d��t|�|d�|�|d��kr|s|tdt|�d�td	|�|d�|�|d�fd
|�|d�|�|d�f�dSqdS)zw
        Check that the orders at nodes (i.e. edges) sum to -k*2 and that lower
        level has lower order.
        rrwr�zWarning: Orders at edge z add up to z instead of -k*2!Fz do not respect level crossing!zPoleorders arezbut levels areT)rrdrr'r�r4rrc)r&r(rT�ordersrrrr�{s>
���������zKLevelGraph.checkedgeorderscs�t�j��_t�j��_�fdd�tt�j��D��_	t
dd��jD���_t
dd��jD���_t
�fdd�tt�j��D��fdd��jD�gdd	d	d
��_dS)a$
        This should be used _only_ for initialisation!

        Make sure everything is in order, in particular:
        * sortedlevels is fine
        * leglist is fine
        * legdict is fine
        * maxleg is fine
        * maxlevel is fine
        * underlying graph is fine
        cs"i|]
}�j|D]}||�q	qSrr|)rrQrr;rrr1�s
��z*KLevelGraph._init_more.<locals>.<dictcomp>cSsg|]	}t|dg��qS�r)�max)rrRrrrrM�r�z*KLevelGraph._init_more.<locals>.<listcomp>cSrJr)r�rrrrrM�rNcrfr��	UG_vertexr,r;rrrM�ric	s6g|]}����|d������|d��|f�qSrv)r�rYryr;rrrM�s.��vertices_and_edgesT��format�loops�
multiedgesN)r3rr�rrr�r5rrrVr��maxleg�maxlevelrr�underlying_graphr;rr;rr!�s
���zKLevelGraph._init_morecCs||j|dfS)z�
        Vertex of the underlying graph corresponding to v.

        Args:
            v (int): vertex number (index of self.genera)

        Returns:
            tuple: tuple encoding the vertex of the Underlying Graph.
        �LG�rr`rrrr��s
zKLevelGraph.UG_vertexcszt�fdd�|D��}t�fdd�|D��}t|�}t�fdd�t|�D��}t�fdd�|D��}t|||||�jj�S)aE
        Extract the subgraph of self (as a KLevelGraph) consisting of vertices
        (as list of indices) and edges (as list of edges).

        Returns the levelgraph consisting of vertices, edges and all legs on
        vertices (of self) with their original poleorders and the original
        level structure.
        c�g|]}�j|�qSrr�r,r;rrrM�riz'KLevelGraph.extract.<locals>.<listcomp>cr�rr|r,r;rrrM�ric�i|]}|��|��qSrrgrr;rrr1�s�z'KLevelGraph.extract.<locals>.<dictcomp>cr�rr_r,r;rrrM�ri)rrr
rr')r&�verticesrZnewvertices�newlegs�newedges�
newpoleorders�	newlevelsrr;r�extract�s	�
�zKLevelGraph.extractcCs&dd�|jdd�D�}|�||���S)z�
        Returns the KLevelGraph associated to a subgraph of underlying_graph
        (with the level structure induced by self)
        cSs g|]}|ddkr|d�qS)r�r�rrrprrrrM�� z8KLevelGraph.levelGraph_from_subgraph.<locals>.<listcomp>T��sort)r�r��edge_labels)r&�Gr\rrr�levelGraph_from_subgraph�sz$KLevelGraph.levelGraph_from_subgraphcs8�fdd���|�D�}|dd��jjdd�D�7}|S)a
        The vertices above (internal) level l (including possible vertices at infinity).

        Used for checking residue conditions.

        Args:
            l (int): internal level number

        Returns:
            list: list of vertices of self.underlying_graph
        crfrr�r,r;rrrM�riz7KLevelGraph.UG_vertices_above_level.<locals>.<listcomp>cSsg|]
}|ddkr|�qS)r��resrrprrrrM�s

�Tr�)r�r�r�)r&rZvertices_aboverr;r�UG_vertices_above_level�s
z#KLevelGraph.UG_vertices_above_levelcCs$|�|�}|�|�}|j�|�}|S)a=
        Subgraph of Underlying Graph (including vertices at infinity) (strictly) above
        (relative!) level l.

        Args:
            l (int): relative level number

        Returns:
            SAGE Graph: subgraph of self.underlying_graph with all vertices strictly
                above level l.
        )r�r�r��subgraph)r&r�
internal_lr��
abovegraphrrr�UG_above_level�s

zKLevelGraph.UG_above_levelcs$�fdd�t�j�D�}�j�|�S)zy
        Subgraph of Underlying Graph without the vertices at infinity.

        Returns:
            SAGE graph
        csg|]	\}}��|��qSrr�)rr-�_r;rrrMr�z3KLevelGraph.UG_without_infinity.<locals>.<listcomp>)r�rr�r�)r&r�rr;r�UG_without_infinityszKLevelGraph.UG_without_infinityc	Cs<t|�|d�|�|d�g�\}}|�|�s-tdt|�d�|j|j|j|j|j	fSt
|j�}t
|j�}t
|j�}t
|j�}t
|j	�}||krS||d7<n#||||7<||||7<|�|�|�|�|�|�|�|�||�|d�||�|d�||d=||d=|||||gS)zZ
        Squish the horizontal edge e and returns the raw data for the new graph.
        rrwr�z- is not a horizontal edge -- Not contracting.)
r3rYr�r�r4rrrrrr�pop�remove)	r&rTrQ�w�	newgenerar�r�r�r�rrr�_squish_horizontals4$
��










zKLevelGraph._squish_horizontalcCs"|�|�|jjg}t|ddi�S)aw
        Squish the horizontal edge e and return the new graph.

        EXAMPLES::

            sage: from admcycles.diffstrata.klevelgraph import KLevelGraph
            sage: G = KLevelGraph.fromPOlist([1,1], [[1,2],[3,4]], [(2,3)], [1,-1,-1,1],[0,0],1)
            sage: G.squish_horizontal((2,3))
            KLevelGraph([2],[[1, 4]],[],{1: 1, 4: 1},[0],1,True)
        r(T)r�rr'r
)r&rT�datrrr�squish_horizontalGs
zKLevelGraph.squish_horizontalcs|dur�S��|���dur"|stdt|��|r �ddfS�S|s+td|d������}��fdd���|�D�}|sDtd|�t�j�}t�j�}t�j�}t�j	�}	t�j
�}
|D]}||
|<q_t||||	|
�jj
d	�}|D]}
|�|
�}qt|r�|d	t|�fS|S)
a�
        Squish the level l (and the next lower level!) and return the new graph.
        If addata=True is specified, we additionally return a boolean that tells
        us if a level was squished and the legs that no longer exist.

        More precisely, adddata=True returns a tuple (G,boolean,legs) where
        * G is the (possibly non-contracted) graph and
        * boolean tells us if a level was squished
        * legs is the (possibly empty) list of legs that don't exist anymore

        Implementation:
        At the moment, we remember all the edges (ee) that connect level l to
        level l-1. We then create a new KLevelGraph with the same data as self,
        the only difference being that all vertices of level l-1 have now been
        assigned level l. We then remove all (now horizontal!) edges in ee.

        In particular, all points and edges retain their numbering (only the level might have changed).

        WARNING: Level l-1 does not exist anymore afterwards!!!

        Downside: At the moment we get a warning for each edge in ee, as these
        don't have legal pole orders for being horizontal (so checkedgeorders
        complains each time the constructor is called :/).
        NF�$Warning: Illegal level to contract: zSquishing levels�andcr�r�r�ry��llr&rrrM�s
�
�z4KLevelGraph.squish_vertical_slow.<locals>.<listcomp>zContracting edgesT)r�r�r4rur�rrrrrrr
rr'r�r)r&r�adddatar(�vv�eer�r�r�r�r�rQZreturngraphrTrr�r�squish_vertical_slowWsH









�	z KLevelGraph.squish_vertical_slowTcs�|dur�S��|�}t||g��|dur,|s tdt|��n�j�j�j�j�jfS��	|���	|�}��fdd��jD�}�fdd�|D�}�fdd�|D�}�fd	d�|D�}g�|r�|�
�\}	}
||	}||
}||	=||
=||�|	�||�|
���|	|
g�||kr�||d
7<n"||||7<||=||D]
}
|||
<||�
|
�q�||=|s`t|�}t���g}g}g}tt�j��D]>}||vr�||vr�|�
||�|�
||dd��|�
|�q�|�
��|��|�
��|�dd��|�
��|��q�g}�jD]!\}	}
|	�v�r%|
�v�s#J��q|
�v�s,J�|�
|	|
f��q�fdd��j��D�}|||||gS)a�
        Squish the level l (and the next lower level!) and return the raw data for the new graph.

        Implementation:
        At the moment, we remember all the edges (ee) that connect level l to
        level l-1. We then create a new KLevelGraph with the same data as self,
        the only difference being that all vertices of level l-1 have now been
        assigned level l. We then remove all edges in ee.

        (In contrast to the old squish_vertical_slow, this is now done in
        one step and not recursively so we avoid a lot of the copying of graphs.)

        In particular, all points and edges retain their numbering (only the level might have changed).

        WARNING: Level l-1 does not exist anymore afterwards!!!

        Args:
            l (int): (internal) level number
            quiet (bool, optional): No output. Defaults to True.

        Returns:
            tuple: raw data of the new graph
        NFr�cs4g|]}t��|d���|d�g��kr|�qSrv)rCrcry)�levelsetr&rrrM�s

��z0KLevelGraph._squish_vertical.<locals>.<listcomp>cr�r�rIrpr;rrr1�sz0KLevelGraph._squish_vertical.<locals>.<dictcomp>cs"i|]
}��|�D]}||�q	qSrrj)rrQrXr;rrr1�s

��cs i|]}|��|�dd��qSrrjrpr;rrr1�r�rwcsi|]\}}|�vr||�qSrr)rrX�p)�deleted_legsrrr1�s��)r�rCr�r4rrrrrrur�r��extend�appendr5rrIrkra�items)r&rr(r�r�rZgenus_of_vertexZ
vertex_of_legZlegs_of_vertex�start�endrQr�rXr�r�r�r�r�r)r�r�r&r�_squish_vertical�s|
�
��
�

�zKLevelGraph._squish_verticalcCs&|j||d�|jjg}t|ddi�S)a�
        Squish the level l (and the next lower level!) and return the new graph.

        In particular, all points and edges retain their numbering (only the level might have changed).

        WARNING: Level l-1 does not exist anymore afterwards!!!

        Args:
            l (int): (internal) level number
            quiet (bool, optional): No output. Defaults to True.

        Returns:
            KLevelGraph: new levelgraph with one level less.

        EXAMPLES::

            sage: from admcycles.diffstrata.klevelgraph import KLevelGraph
            sage: G = KLevelGraph.fromPOlist([1,2], [[1],[2,3,4]], [(1,2)], [0,-2,1,3],[0,-1],1)
            sage: G.squish_vertical(0)
            KLevelGraph([3],[[3, 4]],[],{3: 1, 4: 3},[0],1,True)
        �r(r(T)r�rr'r
)r&rr(r�rrr�squish_verticalszKLevelGraph.squish_verticalcCsn|}|��rtd�t|�Stt|��d��D]}t|�d|kr#q|s*td|�|j|�|�|d�}q|S)af
        Squish all levels except for the k-th.

        Note that delta(1) contracts everything except top-level and that
        the argument is interpreted via internal_level_number

        WARNING: Currently giving an out of range level (e.g.
            0 or >= maxlevel) squishes the entire graph!!!

        Return the corresponding divisor.
        z2Error: Cannot delta a graph with horizontal edges!rwzSquishing levelr�)	r�r�rr�r5r�r�r�r�)r&r'r(r�r-rrr�delta s
zKLevelGraph.deltacsFt�j�����fdd�t����D�t�fdd��jD��f�_dS)aK
        DEPRECATED!! DO NOT USE!!

        Compute a bunch of invariants (as a quick check for not isommorphic).
        Up to now we have:
        * sorted list of genera (by level)
        * number of edges
        * number of levels
        * names and pole orders of marked points
        * sorted list of pole orders
        c�g|]	}|��|�f�qSrrgrr;rrrMXr2z/KLevelGraph._init_invariant.<locals>.<listcomp>crfrrgrr;rrrMZriN)rrr�r3rr��
_invariantr;rr;r�_init_invariantIs


�
�zKLevelGraph._init_invariantcCs|��|jS)z-
        DEPRECATED!!! DO NOT USE!!!
        )r�r�r;rrr�	invariant\szKLevelGraph.invariantc�t��fdd�|��D��S)zZ
        Check if a "vertex isomorphism" preserves the (relative) level structure
        c3s8�|]\}}�j���|���j���|��kVqdSr)r�r�ra)r�sv�ov�rDr&rrrgs���z8KLevelGraph._genisom_preserves_levels.<locals>.<genexpr>��allr��r&rD�dVrr�r�_genisom_preserves_levelscs�z%KLevelGraph._genisom_preserves_levelscr�)zE
        Check if a "leg isomorphism" preserves pole orders.
        c3s(�|]\}}��|���|�kVqdSrrg)r�sl�olr�rrros��z<KLevelGraph._legisom_preserves_poleorders.<locals>.<genexpr>r�)r&rD�dLrr�r�_legisom_preserves_poleordersks�z)KLevelGraph._legisom_preserves_poleorderscs���fdd��jD�S)z�
        Give a dictionary translating the levels of self to other in accordance
        with the dictionary of vertices dV.
        c	s&i|]}|�����|�d��qSr�)rarur�r�rDr&rrr1w��z)KLevelGraph._leveliso.<locals>.<dictcomp>r_r�rrr�	_levelisors�zKLevelGraph._levelisocs:t�j�j�}��fdd�|D�}|rt|�|fSt|�S)aZ
        DEPRECATED!!! Instead, use EmbeddedLevelGraph!!!

        Check if self is isomorphic to other.
        Return boolean + list of isomorphisms if adddata=True.

        Note that our isomorphisms are stgraph isomorphisms plus a dictionary
        translating the level structure of self into that of other.

        At the moment we use admcycles.GraphIsom and check which of these
        preserve the KLevelGraph structure (using the above invariants, though!)
        Probably it would be much faster to reimplement this for KLevelGraphs
        as it seems quite redundant as is...
        cs:g|]\}}���|�r���|�r||���|�g�qSr)r�rr)rr�rr�rrrM�s

�
�z-KLevelGraph.is_isomorphic.<locals>.<listcomp>)r
rP�bool)r&rDr��isomsZ
levelisomsrr�r�
is_isomorphiczs
zKLevelGraph.is_isomorphiccs�t�j�fdd��jD�gdddd�}|�tt�j����fdd��jD�}d}tt�j��D]0���fd	d���	�D�}|sAq0|d
�7}|D]}|d��
|�7}|dt��|��7}qIq0t
|�|jdd
|dd�t|ddddd�S)z�
        Return a sage graphics object generated from a sage graph.

        TODO: Some things that are still ugly:
        * No legs!!
        * currently the vertices have labels (index,genus)
        * loops are vertical not horizontal
        cs0g|]}��|d���|d���|�f�qSrv)rY�prongryr;rrrM�s(�z(KLevelGraph.plot_obj.<locals>.<listcomp>r�Tr�cs&i|]}|�fdd���|�D��qS)cr�rr�rpr;rrrM�r�z3KLevelGraph.plot_obj.<locals>.<dictcomp>.<listcomp>)rurr;rrr1�rz(KLevelGraph.plot_obj.<locals>.<dictcomp>zMarked points: crnrr�rhr�rrrM�rsz
At level %s: �
z
 of order i��ranked)r��vertex_size�heights�layout)rg���������topF)�vertical_alignment�axis_coords�axes)rrr�relabelr[r�rr3rCr�
_pointtyper4rdr��plotr	)r&r��hZlegtextZpoints_at_levelrXrr�r�plot_obj�s:

���
�����zKLevelGraph.plot_obj)Fr)FF)T)H�__name__�
__module__�__qualname__�__doc__r+�classmethodr8r<r>r@r:rErrH�propertyrPrrYr\r^rarcrdrlrur{rkr�r�rIr�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r"r�r�r�r!r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�rrr	rrrrrr
s�T
��

Z
























	




' *

I
e
)
r
N)�copyr�sage.structure.sage_objectr�sage.rings.integer_ringr�sage.misc.flattenr�sage.functions.generalizedr�sage.misc.cachefuncr�sage.graphs.graphr�sage.plot.textr	Zadmcycles.admcyclesr
Zadmcycles.stable_graphrrP�admcycles.diffstrata.sigrr
rrrr�<module>s