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

��c�4�	@sJddlmZddlZddlZddlZzddlmZWney)ddlmZYnwddl	m
Z
ddlmZddl
mZmZmZmZmZddlmZddlmZdd	lmZdd
lmZddlmZmZmZddlm Z dd
l!m"Z"ddl#m$Z$ddl%m&Z&ddl'm(Z(m)Z)m*Z*m+Z+ddl,m-Z-ddl.m/Z/m0Z0m1Z1ddl2m3Z3m4Z4ddl5m6Z6ddl5m7Z7dZ8e(d�a9e(d�a:dd�Z;iZ<e3Z=dd�Z>dd�Z?e d�dd ��Z@d�d!d"�ZAd�d#d$�ZBd�d&d'�ZCGd(d)�d)�ZDd*d+�ZEGd,d-�d-�ZFd.d/�ZGd0d1�ZHe d�d2d3��ZId4d5�ZJd�d6d7�ZKe d�d8d9��ZLd�d:d;�ZMd<d=�ZNd�d>d?�ZOGd@dA�dAe�ZPePZQd�dBdC�ZRdDdE�ZSdFdG�ZTGdHdI�dIe�ZUGdJdK�dK�ZVGdLdM�dM�ZWdNdO�ZXdPdQ�ZYdRdS�ZZe7j[ej\�]e
dT�dUdVdWe7�^ddXg�e7�_�dY�d�d[d\��Z`d�d]d^�Zad�d`da�Zbe d�dbdc��Zcddde�ZdGdfdg�dg�Zed�dhdi�Zfdjdk�Zgd�dldm�Zhe7j[ej\�]e
dT�dUdndWe7jie7jjfdo�d�dpdq��Zkd�drds�Zldtdu�ZmGdvdw�dw�Zndxdy�Zoe dzd{��ZpGd|d}�d}�Zqd�d~d�Zre d�d���Zsd�d��Zt				d�d��Zud�d��Zve7j[ej\�]e
dT�dUd�dWe7�^dXg�e7�_�dY�d�d�d���Zwd�d�d��Zxd�d��Zyd�d��Zzd�d��Z{d�d��Z|d�d��Z}d�d��Z~d�d��Zd�d��Z�d�d��Z�d�d�d��Z�d�d��Z�d�d�d��Z�d�d�d��Z�d�d�d��Z�d�d�d��Z�d�d��Z�e d�d���Z�d�d��Z�d�d�d��Z�d�d�d��Z�d�d�d��Z�d�d�d��Z�d�d�d��Z�d�d��Z�d�d�d��Z�d�d„Z�d�dĄZ�d�dƄZ�d�dȄZ�d�dʄZ�d�d̄Z�d�d΄Z�e d�dЄ�Z�dS)��)�deepcopyN)�Iterable)�DOT_SAGE)�
SageObject)�	factorial�	bernoulli�gcd�lcm�multinomial��binomial)�PermutationGroup)�matrix)�block_matrix)�Permutations�Subsets�
Partitions)�cached_function��prod)�flatten)�vector)�Integer�Rational�QQ�ZZ)�span�)�	MODULI_ST�
get_moduli�socle_degree)�StableGraph�	GraphIsom)�DR)�
file_cacheT�cCsFddlm}|dd�t|�}t|�}|dks|dkrt�|a|adS)Nr��deprecation�mz=reset_g_n is deprecated. Please use TautologicalRing instead.r)�
supersededr'r�
ValueError�g�n)Zgloc�nlocr'�r.�7/home/user/Introduction lectures/admcycles/admcycles.py�	reset_g_n&s
r0cCst|gttd|d��gg�S)z�
    Return the trivial graph in genus `g` with `n` markings.

    EXAMPLES::

        sage: from admcycles.admcycles import trivgraph
        sage: trivgraph(1,1)
        [1] [[1]] []
    r)�stgraph�list�range�r+r,r.r.r/�	trivgraphHs
r5cCs�|dkrt|gttd|d��gg�gSt|||d�}g}|D]}t|���D]	}||�|�7}q(q |s7gS|dg}d}tdt|��D]%}	d}
t|�D]}||	�||�r\d}
nqM|
rj|||	g7}|d7}qE|S)NrrTF)r1r2r3�list_strata�	num_verts�
degenerations�len�
is_isomorphic)r+r,�rZLoldZLnew�G�vZLdupfree�count�i�newgraph�jr.r.r/r6Ws0 �
��r6csf|durd|d|}|d|d|krd|d|}zt�||�\}}d|d|}Wn-ty]td|d|dd�D]}zt�|||�\}}Wn	tyZYqCwYnw|dkr�t|gttd|d��gg�dt�t�ggg}|ddd��gddggg}t|d|d�D�]�}|gg7}g}tt||d��D]7}||d|d}	|	�	�}
|
D]$}t
tt||d|d���}|||��t||fg�tg�gg7}q�q�dd�}
|j|
d	�d}g}g}d}|D]}	|	d��}||k�r
||g7}||dg7}|}|d7}q�|t|�dg7}d}|gggg7}tt|��D]�}g}t||d||dd�D]�}||d}	d
}tt|��D]W}||�|	j
�dd
d�\}}|�r�d}|d�t||d
�dd}t
��fdd�||d|dD��}�d
�||f�||d|d�|||f�n�qM|�r�|||g7}t||d
�dd}t||d
�dd}||d|d�|t|�d|f��q=|||7<||d|dd��g7<||d|dg7<|t|�7}�q*||d|dg7<q�||k�r/|dk�r/tj�|||fdf�||fS)Nr%����������rr.rcSs|d��S�Nr)�	invariant)�or.r.r/�inva��z degeneration_graph.<locals>.inva��keyT��certificateF�c3s"�|]}�d��|�VqdS�rN)�index��.0�h��Gr2�diclr.r/�	<genexpr>�s� z%degeneration_graph.<locals>.<genexpr>)�degeneration_graph�cached�KeyErrorr3r1r2�setrEr9r8�tuple�	halfedges�sortr:�add�cache�pop)r+r,�rmax�deglist�invlist�r0r;�templistr?�GrZdeg_GrZdGr�lisrGZcurrent_invariantZtempbdryZtempinvr>�invZisomclrAZ	new_graph�k�ans�IsoZupstairsZlisnewr.rSr/rW�s����. 
 &�


"("�*�"rWc
sb|��}t|���}|��}�dur|jdd�}|���ndd�td|d�D��|}|��|��}t	|||�\}}||d�
|�}	t||d|	d||d|	dd�D]5}
|j|||
ddd�\}�|r���fdd��D�}|��fd	d�|�
�D��||
�d|fSq\td
t|��t|||f�t|tddd�d��f�dS)NT��mutablecS�i|]}||�qSr.r.�rQr?r.r.r/�
<dictcomp>��zdeggrfind.<locals>.<dictcomp>rrrKcsi|]}|�d�|�qS�rr.�rQ�l��Isom�markdicr.r/rp�csi|]	}|�d|�qSrrr.rs)rvr.r/rp�zHelp, cannot find rM)r+r9�
list_markings�	num_edges�copy�rename_legsr3�
set_immutablerErWrOr:�updater\�print�reprr6)
rfrwr+r,r;Z	Gr_renameZInvrbrcZInvIndexr?rjrUr.rur/�	deggrfind�s,2� r�cs������kr
gS���}����t��}|���kr,td�t��t��td��t��t����kr<td�gS�fdd�td|d�D�}t||����\�}|durbt	�|�\�
�	}�n|\�
�	}�|durvt	�|�\��
}	�n|\��
}	�t�
t
tt���
d���fg�}
t��
d�D]-}t�}|
D]#��|�dd	D]\}
}t
�fd
d�|D��}|�|
|f�q�q�|}
q�t�	fdd�|
D��}|}
t���
d���
d�}t�}|D]"\}�|
D]�t
���
�fd
d��dD��}|��d|f�q�q�|}
g}dd��D�}��
�}��	�
fdd�tt��
�	d��D���fdd���
�D��|
D]�\}�����fdd�|D����|����dk�rbdd�t����D�}n����fdd��D�}tt�����t|�}t�fdd��jdd�D��}t|�}|�rt�}t|�D]e}��|d�|v�rʈ�|d�}|�|�||v�r�|��|d�||<|�|�|�|��q���|d�|v�r���|d�}|�|�||v�r�|��|d�||<|�|�|�|��q�|}|�s�||�fg7}�q:|S)Nz.Error, Astructuring graphs of different generaz"A very specific bad thing happenedz2Error, Astructuring graphs with different markingscsi|]	}�|d|�qSrrr.ro)�markr.r/rp$ryzAstructures.<locals>.<dictcomp>rrCrrMc3s�|]	}�d|VqdSrNr.�rQrA)�morr.r/rV=��zAstructures.<locals>.<genexpr>c3s �|]}|d�kr|VqdS�rNr.)rQr�)�iAr.r/rVB��c3s(�|]}����d|VqdSrNr.r�)�Autolrb�iG�rGr.r/rVL��&cSrnr.r.rPr.r.r/rpSrqcs"i|]
}���d||�qSrrr.ro)rbr��rAr.r/rpU�"c�i|]}�||�qSr.r.rP)�diclGr.r/rpV�cs"i|]
}|����|�qSr.r.rP)�dicAtild�diclA�diclGinverser�r.r/rpYr�cS�i|]}|d�qS�rr.�rQ�verr.r.r/rp^rqc�"i|]
}���|���|��qSr.��vertexrP��A�GammarUr.r/rpdr�c3�$�|]
}|d���vr|VqdSr���values�rQ�e�rUr.r/rVf���F�r|)r{r+rzr9r�r*rZr3rWr�r[r^r"r\rr7�edgesr2r��remove�discard)r�r��
identGamma�identAr+r,rwrcZdicvAZdicvG�	morphismsr;Z
new_morphisms�tar�psi�compositionZAutoZAutovZfinalmorphismsZdicmarkingsZ
Ahalfedges�targ�dicv�remaining_vertices�remaining_edges�current_vertices�newcurrent_verticesr��vnewr.)r�r�r�rbr�rUr�r�r�r�r�r�r�r�r�r/�Astructuress�&�" �*








��r�Fc
s�|��}|���t���d}|��|��kr|}|}|}d}|��dkrt|rt|rN|dd�t|���D�dd�|��D�dd�t|���D�dd��D�fgS|dd�t|���D�d	d��D�d
d�t|���D�d	d�|��D�fgS|r��fdd�t��D�}�fdd�|��D��
�fd
d�|��D���
�|���|�|ji�
dd�}|ji�dd�}t	|�\}}	}
}t	|�\}}
}}t
|�||�\�}g}t|	g�}t|d|d�D]�	t��	fdd�|D��}q�t|
g�}t|||d�D�]X�	|�|�D�]0}��	|d}�	|dd�t|���D�dd�|��D�f}t
|||||	|
|fd�}t
|||||
||fd�}|du�rJt||�}dd�|D�}g}t|���}|D]y\��|D]q\��ttt����t������}||k�r�|�r�|�r�|�|���fdd��D����
fdd��
D�f��qZ|�|����f��qZ|�r�|�|���
fdd��
D����fdd��D�f��qZ|�|����f��qZ�qT|�r,|�r*|�d�\}����|�|����f�|D]<\��z-|�|��fdd��D���fdd��D���fdd��D���fdd��D�f�W�q�t�y&Y�q�w|�sԐq||7}�q�	||k�rQt��	fdd�|D��}t��	fd d�|D��}q�|S)!NFTrcSrnr.r.�rQr=r.r.r/rp�rqz(common_degenerations.<locals>.<dictcomp>cSrnr.r.rsr.r.r/rp�rqcSr�r�r.r�r.r.r/rp�rqcSr�r�r.r�r.r.r/rp�rqcSrnr.r.rsr.r.r/rp�rqcSrnr.r.r�r.r.r/rp�rqc�i|]	}�||d�qSrrr.ro)�mkingsr.r/rp�ryc�i|]	}||�d�qSrrr.rs�r,r.r/rp�rycr�rrr.rsr�r.r/rp�ryrlrc3s2�|]}��d|dD]}|dVqqdS)rr%rNr.�rQr?�d�rbr;r.r/rV�s���z'common_degenerations.<locals>.<genexpr>cSrnr.r.r�r.r.r/rp�rqcSrnr.r.rsr.r.r/rp�rq)r�r�cs&g|]\}�|�fdd��D�f�qS)cr�r.r.rsr�r.r/rp�r�z3common_degenerations.<locals>.<listcomp>.<dictcomp>r.)rQr�r.r�r/�
<listcomp>��&z(common_degenerations.<locals>.<listcomp>c�i|]	}|��|�qSr.r.rs��dl2�renamedicl2r.r/rp�rycr�r.r.rs��dl1�renamedicl1r.r/rp���cr�r.r.rsr�r.r/rp�rycr�r.r.rsr�r.r/rp�r�c�i|]	}|��|�qSr.r.r�)r��dv1r.r/rp�rycr�r.r.rs)�dicltildr�r.r/rp�rycr�r.r.r�)r��dv2r.r/rp�r�cr�r.r.rs)r�r�r.r/rp�ryc3�.�|]}��|dD]}|dVqqdS�r%rNr.r�r�r.r/rV���,c3r�r�r.r�r�r.r/rV�r�)r+rzr9r{r3r7�leglistr�relabelr�rWrZ�intersectionr�r"r2r��appendr`r�r*)�G1�G2�modiso�renamer+�switched�temprw�r1�i1�dicv1�dicl1�r2�i2�dicv2�dicl2rc�commdegZdescendants1Zdescendants2r?r�Z	GammafindZG1structuresZG2structuresZAutGammaZAutGammatildZtempdegZnumlegsZnumcoveredlegsr.)rbr�r�r�r�r�r�r�r,r;r�r�r/�common_degenerations�s�LL



,

 
(�(���6�����
�r�c@s�eZdZd&dd�Zd'dd�Zdd�Zd	d
�Zd&dd�Zd
d�Zdd�Z	dd�Z
dd�Zdd�Zdd�Z
iiifdd�Ziiidfdd�Zdd�Zd d!�Zd"d#�Zd$d%�ZdS)(�GstgraphNcCs>||_||_||_||_||_|dur|��|_dS||_dS�N)r<�gamma�vertact�legact�	character�hurwitz_data�hdata)�selfr<r�r�r�r�r�r.r.r/�__init__�s
zGstgraph.__init__TcCsJt�t�}|j|_|jj|d�|_|j��|_|j��|_|j��|_|S�Nrl)r��__new__r<r�r|r�r�r�)r�rmr<r.r.r/r|s
z
Gstgraph.copycC�
t|j�Sr�)r�r��r�r.r.r/�__repr__�
zGstgraph.__repr__cCstd��)Nzdo not deepcopy)	�RuntimeErrorr�r<rr�r�r�r�r��r��memor.r.r/�__deepcopy__�zGstgraph.__deepcopy__cCs"|dur
|����S|�|���Sr�)�quotient_graph�dim�extract_vertex)r�r=r.r.r/r�szGstgraph.dimc	Cs�|j��s|j��|_|jji|dd�i}i}|jD]}|�|j||j|�||d|�|d|d�f<q|jD]
}|j|||�||�<q;dS)NT��inplacerr)r��
is_mutabler|r�r��getr�)r��diZtemp_legactZtemp_characterrir.r.r/r}!s

6
�zGstgraph.rename_legscCs^g}|jD]}|j||f|kr||g7}qz	|j���|�WSty.|j�|�YSwr�)r<r��
ambient_group�subgroup�AttributeError)r�r?�genr+r.r.r/�vstabilizer.s

��zGstgraph.vstabilizercCsJz|j���|j|dg�WSty$|j�|j|dg�YSwrD)r<rrr�r)r�rAr.r.r/�lstabilizer9s
�zGstgraph.lstabilizercCs,tt|j��gt|j���gg�|��g�Sr�)�
prodHclassr1r�r+r2rz�to_decHstratumr�r.r.r/�
to_prodHclassAs,zGstgraph.to_prodHclassc	s�i}i�i}��|�|�����fdd�t����D�}i�t����D]�}d}||dj��}t||�}�|}g}	�j|dd�D]#}
�jD]}�j||
f�jj|dd�vrf|	�	�j||
f�nqIqDt
�j||dj�\}}
|	D].}
||djD]}|D]}|j||f��j|||
f<q�q�|t|��j|
d7}qwq$g}t�j���D]}||}�fdd��jj|dd�D�}|�	||g�q�t
�jjdd�||�S)NcsJi|]!}|�j��|�t���|��fdd��j|dd�D��f�qS)c�g|]}�j|�qSr.�r�rsr�r.r/r�Ks
�z6Gstgraph.to_decHstratum.<locals>.<dictcomp>.<listcomp>Fr�)r��genera�HurwitzDatar�legsr�)�dicvinv�quotgrr�r.r/rpKs
(��z+Gstgraph.to_decHstratum.<locals>.<dictcomp>rFr�c�i|]}|�|�qSr.r.rs)�
masterdiclr.r/rpkr�rl)r�r3r7r<�order�
trivGgraphrr�r�r��leftcosetactionrr��decHstratumr|)r�r�rU�spacesr=r,ZgordZtGraph�vinvZlegrepsrtr+Zquotrepr�gprime�vertdata�w�aZwdiclr.)rrrr�r/r
EsF
�
��"��zGstgraph.to_decHstratumcCs�|�|�}|jj|dd�}|j�||�}t|j�|�g|g|�}i}|D]}d||df<q$i}|D]}|D]
}	|j||	f|||	f<q5q1i}
|D]	}	|j|	|
|	<qHt|||||
�S)NTr�r)	rr�r�
edges_betweenr1rr�r�r�)r�r?�G_new�lgsZegsZ	gamma_newZvertact_newr+Z
legact_newrAZ
character_newr.r.r/r�rs 
�zGstgraph.extract_vertexcs�|��|��|��t�j���D]}|||<q�j}|j}t||�\�}	�j��t���|��}
t�jj	|jj	�}t
�j|jjdd��}t
�jj|dd��}
||
}i�|D]
}|d7}|�|<qZ|
�
��i�i}�jj|dd�}�D][��j�|f|�<|
��}��fdd�|D�}|�
|�i}i}i��jj|�j�|f|j||�d�|��j�|f�|D]
}|||||<q�����fdd��D��qx|D]h}tt���D]_}tt���D]-}|D](}��|�|j||ff�j�||�|����|�|ff<q�q�||j|d�|��|j|d|j|d	f�j��|�|f<q�qֈ��|����fd
d�|D��|��fdd�t|j���D��dS)NFr�rcsi|]
}|�j�|f�qSr.�r�rs)r+r�r.r/rp��z4Gstgraph.equivariant_glue_vertex.<locals>.<dictcomp>)�divGr�divs�dilc�i|]	}�|f�|�qSr.r.r�)�dil_tempr+r.r/rp�ryrrMcs"i|]
}|��d�|f�qSr�r.r�)�L�augment_dic�
legdiclistr.r/rp�r�csi|]}|�|�qSr.r.r�)�	oldvertnor.r/rp�r�)�clearr3r�r7r<rr9r|�max�_maxlegrZ�unionrr}r��glue_vertexr`rr��inverser��vertact_reconstruct)r�r?rfr$r%r&rAr<�HrZGr_mod�mr�br�rtZorbiZoldlegsiZ	Gr_translZ
transl_dicZ
divGr_tempZ	divs_temp�g1�g2rRr.)r)r*r(r+r+r,r�r/�equivariant_glue_vertex�sd



�2��8��&z Gstgraph.equivariant_glue_vertexFcs|��|��|��tt�j����}g}|D]}|�jj|dd�7}qd}|dd�D]0}||vr^|||<�jD]}	�j|	|f|vrY||�j|	|f<|��j|	|f�q;|d7}q.|dd�D]%��|vr�t	��fdd��jD��}
t
|
�}|
D]}|||<|�|�q~qedd	�t|�D�}
t	|���}|D]�|
|�j����g7<q�g}t|�D]C}��
||���}t�fd
d	�|
|D��}d�j�||�dt|�d|td�}|��r�|dks�td��|t|�g7}q�|��}g}�jjdd�D]'}|d|v�r+||d||dfg7}|�|d�|�||d��qt||
|d
d�}|�r~t|���}dd�t|�D��t����}|��}|D]}||k�s\J�|�|<�qS|ji�d
d��fdd�|��D�}|��|�|�|� �|�!�|S)a{
        Computes the quotient graph of self under the group action.

        dicv, dicl are dictionaries that record the quotient map of vertices and legs,
        dicvinv is a dictionary giving some section of dicv (going from vertices of
        quotient to vertices of self).
        If relabel=False, the legs of the quotient graph are labeled with the
        label of their smallest preimage. Otherwise, the labels are normalized
        to 1,...,n such that the ordering of the labels is preserved.

        EXAMPLES::

            sage: from admcycles.admcycles import trivGgraph, HurData
            sage: G = PermutationGroup([(1, 2)])
            sage: H = HurData(G, [G[1], G[1], G[1], G[1]])
            sage: tG = trivGgraph(1, H); tG.quotient_graph()
            [0] [[1, 2, 3, 4]] []
            sage: H = HurData(G, [G[1], G[1], G[1], G[1], G[0]])
            sage: tG = trivGgraph(1, H); tG.quotient_graph()
            [0] [[1, 2, 3, 4, 5]] []
            sage: H = HurData(G, [G[1], G[1], G[1], G[1], G[1]])
            sage: tG = trivGgraph(1, H); tG.quotient_graph() # no such cover exists (RH formula)
            Traceback (most recent call last):
            ...
            ValueError: Riemann-Hurwitz formula not satisfied in this Gstgraph.

        TESTS::

            sage: from admcycles.admcycles import trivGgraph, HurData
            sage: G = PermutationGroup([(1, 2, 3)])
            sage: H = HurData(G, [G[1]])
            sage: tG = trivGgraph(2, H); tG.quotient_graph()
            [1] [[1]] []
            sage: H = HurData(G, [G[1] for i in range(6)])
            sage: tG = trivGgraph(1, H); tG.quotient_graph()  # quotient vertex would have genus -1
            Traceback (most recent call last):
            ...
            ValueError: Riemann-Hurwitz formula not satisfied in this Gstgraph.

        Check issues related to previous bug in quotient_graph:

            sage: from admcycles.admcycles import StableGraph, HurData, trivGgraph, Htautclass, Hdecstratum
            sage: gamma = StableGraph([0, 0, 1], [[1, 2, 5], [3, 6, 14], [13]], [(5, 6), (13, 14)])
            sage: G = SymmetricGroup(2)
            sage: H = HurData(G,[G[1],G[1],G[0]])
            sage: trivGg = trivGgraph(2, H)
            sage: trivGclass = Htautclass([Hdecstratum(trivGg)])
            sage: A = trivGclass.quotient_pullback(gamma.to_tautological_class())
            sage: all(u.Gr.quotient_graph().is_isomorphic(gamma) for u in A.terms)
            True

        Check that the markings of the quotient graphs are the same for all graphs in a given stratum.

            sage: from admcycles.admcycles import HurData, list_Hstrata
            sage: G = CyclicPermutationGroup(4)
            sage: g = G.gen()
            sage: H = HurData(G, [g, g^2, g^3, g^2])
            sage: all(sorted(G.quotient_graph().list_markings()) == [1, 2, 4, 5] for G in list_Hstrata(2, H, 1))
            True
        Fr�rNrc3s�|]
}�j|�fVqdSr�r"�rQr+)rtr�r.r/rV>��z*Gstgraph.quotient_graph.<locals>.<genexpr>cS�g|]}g�qSr.r.r�r.r.r/r�G�z+Gstgraph.quotient_graph.<locals>.<listcomp>cs&g|]}dtd��j|d�qSrr�rr�rsr�r.r/r�Pr�rMz7Riemann-Hurwitz formula not satisfied in this Gstgraph.TrlcSsi|]	\}}||d�qSrrr.)rQ�new�oldr.r.r/rpbryz+Gstgraph.quotient_graph.<locals>.<dictcomp>r�csi|]	\}}|�|�qSr.r.)rQ�l1�l2)�legdictr.r/rpiry)"r-r2r3r�r7rr<r�r�rZ�minr�r�rr�sumrr�
is_integerr*rr|r�r1�sortedrz�	enumerater.r\r��itemsr�tidy_upr~)r�r�rrUr�Zvertlistr�r=Zcountvr+�orbitZmin_l�llZquot_legZlegsetZquot_generaZGvr6ZqgenusZunused_legsZ
quot_edgesr�Z
quot_graph�markingsZmax_markingr\rRZdicl_newr.)rtrCr�r/r��s|=
��� 0�
zGstgraph.quotient_graphcs.���}t|���}t�j�fdd�|D��S)Ncrr.r
rsr�r.r/r�wr�z)Gstgraph.hurwitz_data.<locals>.<listcomp>)r�rGrzrr<)r�r�marksr.r�r/r�tszGstgraph.hurwitz_datacsX�j��dkr��|��d�Sz���}Wn
tyYdSw|�d�}�j����dkr@t	�fdd�|j
ddd�D��dsZ�dkr\t��fdd�|j
ddd�D���j��kr\dSt
��t�fd	d�|j
ddd�D��}t|�����}d}t|�D]}|d
t	|�t
��t|�d|7}q~|t��fdd�|j
ddd�D��t
��S)a!
        Gives the degree of the delta-map from the Hurwitz space parametrizing the curve
        placed on vertex v to the corresponding stable-maps space.

        Note: currently only works for cyclic groups G.

        EXAMPLES::

          sage: from admcycles.admcycles import trivGgraph, HurData
          sage: G = PermutationGroup([(1, 2)])
          sage: H = HurData(G, [G[1], G[1], G[1], G[1]])
          sage: tG = trivGgraph(1, H); tG.delta_degree(0) # unique cover with 2 automorphisms
          1/2
          sage: H = HurData(G, [G[1], G[1], G[1], G[1], G[0]])
          sage: tG = trivGgraph(1, H); tG.delta_degree(0) # unique cover with 1 automorphism
          1
          sage: H = HurData(G, [G[1], G[1], G[1], G[1], G[1]])
          sage: tG = trivGgraph(1, H); tG.delta_degree(0) # no such cover exists (RH formula)
          0
          sage: G = PermutationGroup([(1, 2, 3)])
          sage: H = HurData(G, [G[1]])
          sage: tG = trivGgraph(2, H); tG.delta_degree(0) # no such cover exists (repr. theory)
          0
        rrrMcs"g|]
}�j|ddkrd�qS�rrMr
rsr�r.r/r��r�z)Gstgraph.delta_degree.<locals>.<listcomp>Fr�csDg|]}�j|ddkr�j|dt�j|d�����qS)rrrM)r�r�inverse_modrs�r,r�r.r/r��sDc�g|]	}�j|d�qSrrr
rsr�r.r/r��ryrCcs"g|]
}t���j|d�qSrrr>rsrQr.r/r��r�)r�r7r��delta_degreer�r*rr<rr9rr�onerr	rZ�ceil�
prime_factorsr)r�r=rrZsigmagcdZprimfacZnumhom�Sr.rQr/rSzs"�

`(*.zGstgraph.delta_degreecs>�j��dkrdd��jD��_dS�fdd��jD��_dS)NrcSsi|]}|dfd�qSr�r.r:r.r.r/rp�r�z0Gstgraph.vertact_reconstruct.<locals>.<dictcomp>csLi|]"}t�j���D]}||f�j��j|�jj|dd�df��qqS)Fr�r)r3r�r7r�r�r)rQr+r=r�r.r/rp�s����)r�r7r<r�r�r.r�r/r3�s

�zGstgraph.vertact_reconstructcPs�i}i}i}�j|||dd�}dd�|��D�}|��D]\}}	||	�|�q|jdd�}
|
���|
j|dd�\}}|sBtd��|\}
}t|���}|d|�d	<|d
|�d<|�	i|�}|d|d
f��j
��dk�r�d}|��d	�}|��d�}|��dkr�d	}n[d}|j
|dd
�|j
|dd
�fD]}t|�dkr�q��fdd�|D�d	}|dus�J�d}t|j
dd
��D]\}}||vr�|}nq�|dus�J�d}|��D]\}}||kr�|}nq�|dus�J���|�}||kr�||gn|g}|j|ddd�d	}i�|j�dd�}i�t|j
j
dd
��}|��D]\}}|D]}	|	|v�r1|	�|<n�q$�q��fdd�t|j
dd
��D�}t|���}|d|�d	<|d
|�d<|j	i|dd�|d|d
f}|��|g|_|��|�||�} �fdd�tt| ��D�}!tt| ��D]
}"|!|"�|| |"��q�|!S�j
��dk�r�|g}#|��d
k�r�dd�|�d	d�D��������r�tj��fdd�tdt��d�D��D]}$i}|$D]
\}}	|	||<|||	<�q�|#�|�	i|���q�g}%�j���r��j}&|&� ��	|&�!�}'|'D]}(|(� ��	k�r|(})n�q
i}*i}+|)},td�	d�D]}"|"�	|*|,<|,|+|"�	<|,|)},�q)i�i}-i�
|#D�]�}t"|�#��}|�$��|D]D}.||.d	}/�j%|/d�|.<|*�j%|/d	�|.t&�	��'�}0�j%|/d
|0�(�|.��|.|-|.<|-|.�(�|.��
|.<�qU|��d
k�r�|j
d	dd
�}1|j
ddd
�}2�d	|1v�r�|1��d	�|2��d�n|1��d�|2��d	�|1|2}3t)�fdd�|1D��}4t)�fdd�|2D��}5tdt*�	�|4d�D�]�}6tdt*�	�|5d�D�]�}7|6|4�|7|5}8��+�	��r�|8�+�	��r�t)�|8��	k�r�t&t,���
fdd�|1D����'�}9t*����-|9��t&|9��t&����'�}:�|:};|:�(��}<|;�(��}=|1dd�}>|2dd�}?i�|1�r�d	g�|1d	<|>�.d	�|2�r�t/tt-��	|8����|2d	<|?�.d	�n|2�r�d	g�|2d	<|?�.d	�|>D]
}@t/t�	����|@<�q�|?D]
}@t/t�	|8���|@<�q�tj0�fdd�|3D��}A�d
|�1d	�d
�t,�fdd�|1D��dt&d��t&d
�d�'��|8d
|�1d�d
|8t,�fdd�|2D��dt&d��t&d
�d�'���d	k�s&�d	k�r(�q�fdd�t�	��D��fdd�tt&�	�|8�D�}Bd d�t�	��	|8�D�}C�j2��}D�j
��}E�j%��}F�j
j3d}G�j
j3d}Htt*�	���D]l}"|C|"�	�|Hg7<|C|"�	|8�	�|Hdg7<|E|H|Hdfg7}E|G|Hd
|Gd
�	�|D|)|Hf<|D|)|Hfd|D|)|Hdf<|+�	��	�|<f|F|H<|+�	��	�|=f|F|Hd<|Hd
7}H�qvtd
�	d�D]*}It|G|Gd
�	��D]}H|D|)|D|+|Id�	|Hff|D|+|I�	|Hf<�q��q�|AD]�}Jd!d�|CD�}Ktt|1��D]/}.t�	�|3|.�D]!}"|K|J|.|"�	��j2|+|"||3|.d	fg7<�q2�q&tt|1�t|3��D]3}.t�	�|3|.�D]%}"|K|J|.|"�	|8�	��j2|+|"||3|.d	fg7<�qk�q_t4|&t5|B|K|E�i|D|F�j6d"����7�t8�fd#d�|%D���s�|%�g7}%�q�q�q�|��dk�r�|j
d	dd
�}3|3��d	�|3��d�t)�fd$d�|3D��}Ltdt*�	�|Ld�D�]}M|M|L�
�
�+�	��r�
�9�D�]��	�
fd%d�tt*�	�d
�
d�D�D�]�}N�fd&d�t��D�D�]�}:|Nd	k�r8|:t&��d
k�r8�q%�|:};t:|:��(��}<t:|;��(��}=|3dd�}Oi�|3�rad	g�|3d	<|O�.d	�|OD]
}@t/t�	�
���|@<�qctj0�fd'd�|3D��}A�
d
|�1d	�d
�
t,�fd(d�|3D��d
t&d
��t&d
�d�'���d	k�r��q%�fd)d�t�	�
�D�}Bd*d�t�	�
�D�}C�j2��}D�j
��}E�j%��}F�j
j3d}G�j
j3d}Htt*�	���D]j}"|C|"�	�
|Hg7<|C|"|N�	�
|Hdg7<|E|H|Hdfg7}E|G|Hd
|Gd
�	�|D|)|Hf<|D|)|Hfd|D|)|Hdf<|+�	��	�|<f|F|H<|+�	��	�|=f|F|Hd<|Hd
7}H�q�td
�	d�D]*}It|G|Gd
�	��D]}H|D|)|D|+|Id�	|Hff|D|+|I�	|Hf<�qf�qY|AD]d}Jd+d�|CD�}Ktt|3��D]/}.t�	�|3|.�D]!}"|K|J|.|"�	�
�j2|+|"||3|.d	fg7<�q��q�t4|&t5|B|K|E�i|D|F�j6d"����7�t8�fd,d�|%D���s�|%�g7}%�q��q%�q�q�q�qE|%St;d-�gSdS).a�
        For a codimension 1 degeneration dege of self.quotient_graph(relabel=True) list all
        degenerations [G0, ...] of self such that Gi.quotient_graph(relabel=True) is isomorphic to dege.
        contracted_edge is the edge of dege that needs to be contracted to obtain
        a graph that is isomorphic to self.quotient_graph(rename=True).
        If dege has more than two vertices, we do not guarantee that the graphs Gi are
        unique up to isomorphism.
        T)r�rrUr�cS�i|]}|g�qSr.r.rsr.r.r/rp�rqz*Gstgraph.degenerations.<locals>.<dictcomp>rlrKzsThe supplied graph and edge contraction do not give rise to a graph isomorphic to self.quotient_graph(relabel=True)rrrMNFr�c�g|]}|�vr|�qSr.r.rs)�contracted_edger.r/r���z*Gstgraph.degenerations.<locals>.<listcomp>)r�rm)rUr�cs"i|]
}|�vr|��|�qSr.r.rs)�dicl_pre_v0_section�dicl_v0r.r/rps�r�csg|]}����qSr.r�r�r�r.r/r�!�cSsg|]}tt|���qSr.)r[rGr�r.r.r/r�.r[c3s�|]	}t��|�VqdSr�)�	itertools�combinations�rQr;)rr.r/rV1r�z)Gstgraph.degenerations.<locals>.<genexpr>c�g|]}�|�qSr.r.�rQ�alpha�r�r.r/r�kr^crbr.r.rcrer.r/r�lr^cs$g|]}t���|�|�qSr.�rrc)r��n1�nur.r/r�x�$crbr.r.r���possir.r/r��r^c� g|]}dtd��|�qSrrrfrcrer.r/r��� crlrrrfrcrer.r/r��rmc�g|]}��qSr.r.r�)r7r.r/r��r=crnr.r.r�)r8r.r/r��r=cSr<r.r.r�r.r.r/r��r=cS�g|]}|dd��qSr�r.rsr.r.r/r��r[�r�c3��|]}t|��VqdSr���
equiGraphIsom�rQr<��
new_Ggraphr.r/rV����crbr.r.rcrer.r/r��r^cs"g|]
}t|���dkr|�qSrr�r�rQ�x)r,�n0r.r/r��r�csg|]}t|��dkr|�qSrrrxr�)�e_newr.r/r��rxcrbr.r.r�rjr.r/r��r^crlrrrfrcrer.r/r��rmcrnr.r.r�)�gen0r.r/r��r=cSr<r.r.r�r.r.r/r��r=cSror�r.rsr.r.r/r�r[c3rqr�rrrtrur.r/rV$rwz4Degenerations for non-cyclic groups not implemented!)<r�r�rIr�r|�
contract_edger:r*r.r�r�r7r�rr9rHr��extract_subgraphrr��_edgesr~r8r3r9rr�r_�chain�
from_iterabler<�	is_cyclicr�gensrZr��difference_updater�r�floorrPr	r�dividesrErr`r2�productrr�r/r�r1r�r3�any�divisorsrr�)Pr�ZdegerZr�rrUZ
quot_GraphZdicl_prerArBZ
dege_contrZis_iso�dicts�_rCZmax_legr=Zv1_degeZv2_degeZl_degerZv_quot�v_tmp�v1�v2�v0Zdege_subZv0_quotZlegs_v0�ls�lmZcontracted_edge_subr)�MrAZ
quot_degenr��degenr<ZGgenerators�ge�sigmaZGtoNumZNumtoG�murirdZ	alpha_prer;�I1�I2�IZn1_minZn2_minZn1_addZn2_add�n2�A1Znu1�nu2�k1�k2ZI1_tempZI2_tempr?Z	mark_dist�
new_genera�new_legsZ
new_legact�	new_edgesZ
new_character�m0r5Zjplus�mdZ
new_legs_plusZn0_minZn0_add�g0ZI_tempr.)rZr\r]r�r|rr7r8r}r,r{rgrvrhrkr�r/r8�sT

 ��

���
,�

&(($



�
$����$����8


&$��
�� 
���
�
��`.
N�



"$��
���
�
�����K���zGstgraph.degenerationsr��T)�__name__�
__module__�__qualname__r�r|r�r�r�r}rrrr
r�r9r�r�rSr3r8r.r.r.r/r��s&

	

-[
1r�c	s~�j|jkrgSt�j|j�}g}|D]�}d}�j��D]�}|dD]}|d�j||f|j||d|fkr>d}nq"|dD]�|d�j|�f|j||d�fkr_d}nqC|dD]O�|sjnJ��fdd�t�j�d�D�D]7}�j�d||j|d�dkr�|�j�d|j|d�d�j�ddks�d}nq{qdq|r�||g7}q|S)NTrFrcs(g|]}t|�j�d�dkr|�qSrr)rr��rQ�t��Gr1rtr.r/r�L�(z!equiGraphIsom.<locals>.<listcomp>rM)r<r"r�r�r�r�r3r�)	r�rTrkZGIsor�ZGequivr+r=rAr.r�r/rs2s:,�,�&b�
�rsc@s<eZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
S)rcCs||_||_dSr��r<rt)r�r<rtr.r.r/r�_s
zHurwitzData.__init__cCs&t|t�sdS|j|jko|j|jkS�NF)�
isinstancerr<rt�r��otherr.r.r/�__eq__cs
zHurwitzData.__eq__cCst|jt|j�f�Sr�)�hashr<r[rtr�r.r.r/�__hash__h�zHurwitzData.__hash__cCst|j|jf�Sr�)r�r<rtr�r.r.r/r�k�zHurwitzData.__repr__cCst|j|j���Sr�)rr<rtr|r�r.r.r/r�nszHurwitzData.__deepcopy__cs(|j���t��fdd�|jD��}|S)Nc3s�|]	}�|dVqdSrNr.ra�r+r.r/rVsr�z'HurwitzData.nummarks.<locals>.<genexpr>)r<rrrErt)r��Nr.r�r/�nummarksqs
zHurwitzData.nummarksN)	r�r�r�r�r�r�r�r�r�r.r.r.r/r^srcCst|dd�|D��S)NcSs$g|]}||��t|��d�f�qSrr)rrDrPr.r.r/r�{rizHurData.<locals>.<listcomp>)rr�r.r.r/�HurDatazr�r�cCs|j}i}|jD]}d||df<qd}i}i}|jD][}|�|dg�}	t||	�\}
}|D]}tt|
��D]}|||fd||||d|f<q5q-tt|
��D]}|
||d|
|��|d|df||d|<qQ|t|
�7}qt|gttd|d��gg�}
t	||
||||d�S)NrrrMrp)
r<rtrrr3r9r2r1r2r�)r�Dr<r�r+r,r�r�r�r4r)�dicrAr�r.r.r/r�s&

&�8rc	s�t||�����}t|j�}|dus|d|d|kr$d|d|}d}td|dtdd�D]}z
t�|||�}Wn	t	yGYq2w|dkrTt||�ggg}t
|||�d}tt|dd�|d�D]i}|�g�||D]]\}	�}
}g}t
t|
��\}
}�fdd�|D�}t|	������|�t��d	ks�J�tt���}||d|
D]}|�|	|�D]�t�fd
d�|D��s�|���q�q�|d�|�qsqh||kr�|dkr�tj�|||fdf�|S)
a�
    Returns a nested list L where L[r][i] is a (duplicate-free) list of all Gstgraphs G for which
    G.quotient_graph(relabel=True) is isomorphic to the graph given by degeneration_graph(...)[r][i].

    EXAMPLES::

        sage: from admcycles.admcycles import degeneration_graph, Hcovers_degeneration_graph, HurData
        sage: G = CyclicPermutationGroup(2)
        sage: g = G.gen()
        sage: H = HurData(G, [g, g, g, g])
        sage: degGr = degeneration_graph(0, 4)[0]
        sage: Hcovs = Hcovers_degeneration_graph(1, H)
        sage: for r in range(2):
        ....:     for l_Ggr, (stGr, _, _, _) in zip(Hcovs[r], degGr[r]):
        ....:         assert all(Ggr.quotient_graph(relabel=True).is_isomorphic(stGr) for Ggr in l_Ggr)
    Nr%rCrBrrcrbr.r.rP)r\r.r/r��r^z.Hcovers_degeneration_graph.<locals>.<listcomp>rMc3s�|]}t�|�VqdSr�rr)rQr4�r<r.r/rV���z-Hcovers_degeneration_graph.<locals>.<genexpr>r.)rr�r+r9rtr3r,�Hcovers_degeneration_graphrXrYrWr.r��next�iterrZr\r�r[rGr8r�r_r`)r+r4ra�g_base�n_baserd�covermapZdegGrr;rfZedge_contractionsr�reZgr_indexZhalfedgeimagesZhalfedges_in_imagerZZcover_contractedr.)r<r\r/r��sH
�


���r�cCs`|dkr
t||�gSt||�����}t|j�}|d|d|kr$gSt|||�}t||�S)zz
    Gives a (duplicate-free) list of Gstgraphs for the Hurwitz space of genus g with HurwitzData H in codimension r.
    rr%)rr�r+r9rtr�r)r+r4r;r�r�r�r.r.r/�list_Hstrata�s
r�cs�|dur-|j����d���dt�fdd�|jD��dd}|��s)J�t|�}���dkr9t||�gS�j	dd�d��j
dd	�}|���t��fd
d�t
|||�D��S)a�
    For a given stabel graph list all possible H-covers.
    The markings of Gr must be [1, ..., len(H.l)].
    If g is not given, it is computed from Gr and H.

    EXAMPLES::

        sage: from admcycles.admcycles import list_Hcovers, HurData, stgraph, trivGgraph, equiGraphIsom
        sage: G = CyclicPermutationGroup(2)
        sage: g = G.gen()
        sage: H = HurData(G, [g, g, g, g])

        sage: Gr = stgraph([0], [[1,2,3,4]], [])
        sage: list_Hcovers(Gr, H)
        [[1] [[1, 2, 3, 4]] []]

        sage: Gr = stgraph([0, 0], [[1,2,5], [3,4,6]], [(5,6)])
        sage: list_Hcovers(Gr, H)
        [[0, 0] [[5, 7, 1, 2], [6, 8, 3, 4]] [(5, 6), (7, 8)]]

        # Test that a previous bug in Gstgraph.degenerations is fixed
        sage: H = HurData(G, [g*g, g, g])
        sage: gr = stgraph([1, 0], [[4], [2, 3, 1, 5]], [(4, 5)])
        sage: list_Hcovers(gr, H)
        [[1, 1, 0] [[5], [7], [6, 8, 3, 4, 1, 2]] [(5, 6), (7, 8)],
         [1, 0] [[5, 7], [6, 8, 3, 4, 1, 2]] [(5, 6), (7, 8)]]
    NrMc3s(�|]}�|d|ddVqdSrNr.rs)r�r.r/rVr�zlist_Hcovers.<locals>.<genexpr>rFr�Trlcsg|]}|�����qSr.)r8rt)rfrZr.r/r�s�z list_Hcovers.<locals>.<listcomp>)r<rr+rErtrFrr{rr�r|r~r�list_Hcovers)rfr4r+ZGr_contrr.)rfrZr�r/r��s
4

�r�c

s�t|||�}g}|D]^}i�i�i�|�����}|r_t|�}|d�|d��fdd��D���fdd��D�}	|�||d��fdd��D���fdd��D���fd	d��D�|	g�q
|�|���g�q
|S)
NrMr%cr�r.r.r�)�defaultdicvr.r/rp:r�z#list_quotgraphs.<locals>.<dictcomp>cr�r.r.rs)�defaultdiclr.r/rp;r�rcr�r.r.r�)r�r�r.r/rp=rycr�r.r.�rQr)�defaultdicvinvrr.r/rp=r�cr�r.r.rs)r�rUr.r/rp>ry)r�r�r�r�)
r+r4r;�localizeZHgr�result�grZqgrZdgfindZdefaultdiclinvr.)r�r�r�rUr�rr/�list_quotgraphs-s(*��r�cs8�durtttd|d���}|��d�n���}i�i}tt|��D]>}t|�t||�}tt||��D])}	|||	dt||��|||	<�t||�|||f||||	<q8q$��fdd��D����td|d�D]}	���������fdd��D����qvt||i�|�}
|
�	�|
S)Nrrcr'r.r.�rQri)�perm_dicr�r.r/rp_ryz"cyclicGstgraph.<locals>.<dictcomp>rMcs"i|]
}�|f���|f�qSr.r.r�)r�r��mu2r�r.r/rpdr�)
r
r[r3r��parentr9rrr�r3)rfr,�permZchar�r<r�Zcyclenor�rA�Gr_newr.)r�r�r�r�r�r/�cyclicGstgraphNs*((�r�cs�|j|dd���fdd�tt���D�}i}|D]&}tt���D]}|||}tt���D]}|�|vr<||||f<q.q q||fS)N�left)�sidecsg|]}�|d�qSr�r.ro��Cr.r/r�vr[z#leftcosetaction.<locals>.<listcomp>)�cosetsr3r9)r<r4r)r�r+r?ZgtildrAr.r�r/rts���rcCs�ddlm}m}|s(|dus|dur!ddlm}|dd�td�S|||���St||�r/|St|tt	f�rW|durA|dj
��}|durPtt|dj
�
���}|||�|�Std��)	a�
    Construct a tautological class.

    The return object has type :class:`admcycles.tautological_ring.TautlogicalClass`.

    INPUT:

    arg : a tuple or list of :class:`decstratum`

    g : integer
      the genus

    n : integer
      the number of marked points

    EXAMPLES::

        sage: from admcycles.admcycles import *

        sage: gamma = StableGraph([1,2],[[1,2],[3]],[(2,3)])
        sage: ds1 = decstratum(gamma, kappa=[[1],[]]); ds1
        Graph :      [1, 2] [[1, 2], [3]] [(2, 3)]
        Polynomial : (kappa_1)_0
        sage: ds2 = decstratum(gamma, kappa=[[],[1]]); ds2
        Graph :      [1, 2] [[1, 2], [3]] [(2, 3)]
        Polynomial : (kappa_1)_1
        sage: t = tautclass([ds1, ds2])
        sage: (t - gamma.to_tautological_class() * kappaclass(1,3,1)).is_zero()
        True

        sage: t = 7*fundclass(0,4) + psiclass(1,0,4) + 3 * psiclass(2,0,4) - psiclass(3,0,4)
        sage: s = t.FZsimplify(); s
        Graph :      [0] [[1, 2, 3, 4]] []
        Polynomial : 7 + 3*(kappa_1)_0
        sage: u = t.FZsimplify(r=0); u
        Graph :      [0] [[1, 2, 3, 4]] []
        Polynomial : 7

        sage: t = kappaclass(1,1,1)
        sage: t.evaluate()
        1/24

        sage: t = psiclass(1,2,1)
        sage: s = t.forgetful_pushforward([1]); s
        Graph :      [2] [[]] []
        Polynomial : 2
        sage: s.fund_evaluate()
        2

        sage: a = psiclass(1,2,3)
        sage: t = a + a*a
        sage: t.degree_list()
        [1, 2]

        sage: diff = kappaclass(1,3,0) - 12*lambdaclass(1,3,0)
        sage: diff.is_zero()
        False
        sage: diff.is_zero(moduli='sm')
        True

    Non-standard markings::

        sage: gamma = StableGraph([1],[[3,7]],[])
        sage: ds = decstratum(gamma, kappa=[[1]])
        sage: tautclass([ds])
        Graph :      [1] [[3, 7]] []
        Polynomial : (kappa_1)_0
        sage: tautclass([ds]).parent()
        TautologicalRing(g=1, n=(3, 7), moduli='st') over Rational Field

    Test the ``g`` and ``n`` parameters::

        sage: tautclass([], g=2, n=2)
        0
        sage: tautclass([], g=2, n=2).parent()
        TautologicalRing(g=2, n=2, moduli='st') over Rational Field
    r��TautologicalRing�TautologicalClassNr&r(zXcan not guess g, n from the input, return an integer. Please provde g and n to tautclassrzinvalid input for tautclass)�tautological_ringr�r�r)r'r�zeror�r[r2r�r+rGrz�	TypeError)�argr+r,r�r�r'r.r.r/�	tautclass�s N

r�c@s�eZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zdd
�Z	dd�Z
dd�Zd0dd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd1d$d%�Zd1d&d'�Zd(d)�Zd*d+�Zd2d-d.�Zd/S)3�KappaPsiPolynomiala�
    Polynomial in kappa and psi-classes on a common stable graph.

    The data is stored as a list monomials of entries (kappa,psi) and a list
    coeff of their coefficients. Here (kappa,psi) is a monomial in kappa, psi
    classes, represented as

    - ``kappa``: list of length self.gamma.num_verts() of lists of the form [3,0,2]
      meaning that this vertex carries kappa_1**3*kappa_3**2

    - ``psi``: dictionary, associating nonnegative integers to some legs, where
      psi[l]=3 means that there is a psi**3 at this leg for a kppoly p. The values
      can not be zero.

    If ``p`` is such a polynomial, ``p[i]`` is of the form ``(kappa,psi,coeff)``.

    EXAMPLES::

        sage: from admcycles.admcycles import kppoly
        sage: p1 = kppoly([([[0, 1], [0, 0, 2]], {1:2, 2:3}), ([[], [0, 1]], {})], [-3, 5])
        sage: p1
        -3*(kappa_2)_0*(kappa_3^2)_1*psi_1^2*psi_2^3 + 5*(kappa_2)_1
    cCs(||_||_t|j�t|j�ksJ�dSr�)�monom�coeffr9)r�r�r�r.r.r/r�szKappaPsiPolynomial.__init__cCr�r�)�boolr�r�r.r.r/�__bool__	r�zKappaPsiPolynomial.__bool__cCs0t�t�}dd�|jD�|_|jdd�|_|S)z�
        TESTS::

            sage: from admcycles.admcycles import kppoly
            sage: p = kppoly([([[], [0, 1]], {0:3, 1:2})], [5])
            sage: p.copy()
            5*(kappa_2)_1*psi_0^3*psi_1^2
        cSs&g|]\}}dd�|D�|��f�qS)cSror�r.ryr.r.r/r�r[z6KappaPsiPolynomial.copy.<locals>.<listcomp>.<listcomp>r�)rQri�pr.r.r/r�r�z+KappaPsiPolynomial.copy.<locals>.<listcomp>N)r�r�r�r�)r��resr.r.r/r|s
	zKappaPsiPolynomial.copycst�fdd�tt���D��S)Ncrbr.r.ror�r.r/r�r^z/KappaPsiPolynomial.__iter__.<locals>.<listcomp>)r�r3r9r�r.r�r/�__iter__szKappaPsiPolynomial.__iter__cCs|j||j|fSr�)r�r��r�r?r.r.r/�__getitem__szKappaPsiPolynomial.__getitem__cCr�r�)r9r�r�r.r.r/�__len__ r�zKappaPsiPolynomial.__len__cC�d|S�NrCr.r�r.r.r/�__neg__#r�zKappaPsiPolynomial.__neg__c	Cs�|dkr|��S|��}|D]L\}}}z&|j�||f�}|j||7<|j|dkr8|j�|�|j�|�WqtyZ|dkrX|j�|dd�|��f�|j�|�Yqw|S)a�
        TESTS:

        Check that mutable data are not shared between the result and the terms::

            sage: from admcycles.admcycles import kappacl, psicl
            sage: A = kappacl(0,2,2)
            sage: B = psicl(3,2)
            sage: C = A + B
            sage: C.monom[1][1].update({2:3})
            sage: A
            (kappa_2)_0
            sage: B
            psi_3
        rN)r|r�rOr�r`r*r�)r�r�r?rir��c�indr.r.r/�__add__&s$���zKappaPsiPolynomial.__add__rcCs6|jsdS|j|\}}tdd�|D��t|���S)Nc�*g|]�t�fdd�tt���D���qS)c3� �|]}|d�|VqdSrNr.r���kvecr.r/rVLr�z4KappaPsiPolynomial.deg.<locals>.<listcomp>.<genexpr>�rEr3r9�rQr.r�r/r�L�*z*KappaPsiPolynomial.deg.<locals>.<listcomp>)r�rEr�)r�r?�kappar�r.r.r/�degGszKappaPsiPolynomial.degc
s�t|j�dkrtgg�St|jdd�}t|��dd�t|�D��|D]}�||�|�q$tgg�}|D]6\��}��fdd��D�}tdd�t��D�|fgdg�}t���fdd�t|�D��}	||||	7}q7|S)	NrcSr<r.r.ror.r.r/r�Wr=z4KappaPsiPolynomial.graphpullback.<locals>.<listcomp>c�i|]	}�|�|�qSr.r.rs)rUr�r.r/rp^ryz4KappaPsiPolynomial.graphpullback.<locals>.<dictcomp>cSr<r.r.ror.r.r/r�_r=rc�4g|]�t����fdd�tt����D���qS)c�4g|]�t��fdd���D������qS)c�g|]
}t|�d���qSrr��kappaclr��ri�numvertr.r/r�br#zJKappaPsiPolynomial.graphpullback.<locals>.<listcomp>.<listcomp>.<listcomp>�rEr�)r�r�preimr=�rir/r�b�,�z?KappaPsiPolynomial.graphpullback.<locals>.<listcomp>.<listcomp>�rr3r9r�)r�rr�r=r/r�b�
��)r9r��kppolyr3r�r)
r�r�rUZnumvert_selfr=�
resultpolyr��psipolydict�psipoly�	kappapolyr.)rUr�rrr�r/�
graphpullbackPs 

 �z KappaPsiPolynomial.graphpullbackcsLtt�j��D]��j�d���fdd��j�dD�f�j�<q�S)z7
        Rename the legs according to ``dic``.
        rcs(i|]}��||��j�d|�qSrr)rr�rs�r>r�r�r.r/rpms���z2KappaPsiPolynomial.rename_legs.<locals>.<dictcomp>r�r3r9r�)r�r�r.rr/r}hs
�zKappaPsiPolynomial.rename_legscCsttt|j��D]0}dd�t|�D�|j|ddd�t||t|j|d��D�|j|df|j|<q|S)NcSr<r.r.ror.r.r/r�tr=z6KappaPsiPolynomial.expand_vertices.<locals>.<listcomp>rrr)r��startrr>r.r.r/�expand_verticesrs$��z"KappaPsiPolynomial.expand_verticescCs|dkr|��SdSrDr�r�r.r.r/�__radd__xs�zKappaPsiPolynomial.__radd__csBt�t�rt�fdd�|jD��fdd�|jD����S|���S)Nc	s`g|],\���jD]$\����fdd�tt���D���fdd�tt��t���D�f�q	qS)csg|]}t�|�|��qSr.)�kappaaddro)�kappa1�kappa2r.r/r�~rxz9KappaPsiPolynomial.__mul__.<locals>.<listcomp>.<listcomp>cs&i|]}|��|d���|d��qSr��rrs)�psi1�psi2r.r/rp~r�z9KappaPsiPolynomial.__mul__.<locals>.<listcomp>.<dictcomp>)r�r3r9rZr2r��r�)rrrrr/r�~s`z.KappaPsiPolynomial.__mul__.<locals>.<listcomp>cs g|]}�jD]}||�qqSr.)r��rQrr6rr.r/r�~rm)r�rr�r��consolidate�__rmul__r�r.rr/�__mul__|s
.
zKappaPsiPolynomial.__mul__cCsDt|t�r
|�|�S|��}tt|��D]}|j||9<q|Sr�)r�rr#r|r3r9r��r�r�r?r?r.r.r/r"�s

zKappaPsiPolynomial.__rmul__cCs"t|tttf�rt||g�SdSr�)r�rr�intr)r��exponentr.r.r/�__pow__�s�zKappaPsiPolynomial.__pow__Fc	Cs>|rd}d}d}d}d}d}	nd}d}d}d	}d
}}	ddd
�}
g}t|�D]J\}}
g}t|
�D]*\}}|rZ|d7}|�|dkrP|||
||�||
||	�n|||
||��q0|rp|�d|d�d�|�|
||���q&|��D]$\}}|�|dkr�|||
||�||
||	�n|||
||��qud�|�S)zV
        Return the string representation of the monomial ``kappa``, ``psi``.
        uκuψ�u₀₁₂₃₄₅₆₇₈₉u⁰¹²³⁴⁵⁶⁷⁸⁹r�r�r��^�
0123456789�-csB|dkrt�|dkr�dSd��fdd�tt|��d��D��S)Nrr(c3s�|]}�|VqdSr�r.)rQr���
digits_strr.r/rV���zDKappaPsiPolynomial._monomial_str.<locals>.num_str.<locals>.<genexpr>�
)r*�join�reversedr�digits)r,r-�minusr.r,r/�num_str�s
&z1KappaPsiPolynomial._monomial_str.<locals>.num_strrz({})z{}�*N)r+)rHr��formatr0rI)r�r�r��unicodeZ
kappa_nameZpsi_nameZindex_prefixZexponent_prefix�indices�	exponentsr4r�r=Zkappa_vZ	kappa_strr��powerr?rAr.r.r/�
_monomial_str�s6
@�&�B
z KappaPsiPolynomial._monomial_strc	Cs$d}tt|j|j��D]�\}\}}t|�}|j|d|d|d�}d|dd�vp0d|dd�v}|r[|ddkrW|sE|d7}t|�}n|sR|d7}|dd�}n	|d7}n|d7}|sb||7}q|ro|d	|d
|7}q|dkrx||7}q|dkr�|d|7}q||d
|7}q|r�|SdS)Nr(rr)r�r�r7�+r+z - z + �(z)*�1z-1r5�0)rH�zipr�r�r�r;)	r�r7r�r?r�r5�cs�msZhas_add_or_subr.r.r/�str�s2 


zKappaPsiPolynomial.strcCs|jdd�S)a�
        TESTS::

          sage: from admcycles.admcycles import KappaPsiPolynomial
          sage: x = polygen(ZZ)
          sage: m1 = ([[0,1,1]], {1: 2})
          sage: m2 = ([[1,0,1]], {})
          sage: m3 =([[]], {1:1})
          sage: m4 = ([], {1:1,2:1})
          sage: m5 = ([[]], {})
          sage: KappaPsiPolynomial([m1, m2, m3, m4, m5], [x-1, -1, x+2, -3, - x + 3])
          (x - 1)*(kappa_2*kappa_3)_0*psi_1^2 - (kappa_1*kappa_3)_0 + (x + 2)*psi_1 - 3*psi_1*psi_2 - x + 3

          sage: m1 = ([[]], {1:1})
          sage: m2 = ([[]], {})
          sage: KappaPsiPolynomial([m1, m2], [3, 4])
          3*psi_1 + 4
        F�r7)rCr�r.r.r/�_repr_�szKappaPsiPolynomial._repr_cCsddlm}||jdd�g�S)u�
        TESTS::

          sage: from admcycles.admcycles import KappaPsiPolynomial
          sage: x = polygen(ZZ)
          sage: m1 = ([[0,1,1]], {13: 25})
          sage: m2 = ([[1,0,1] + [0] * 10 + [1]], {})
          sage: m3 =([[]], {1:123})
          sage: m4 = ([], {1:1,2:1})
          sage: m5 = ([[]], {})
          sage: p = KappaPsiPolynomial([m1, m2, m3, m4, m5], [x-1, -1, x+2, -3, - x + 3])
          sage: unicode_art(p)
          (x - 1)*(κ₂*κ₃)₀*ψ₁₃²⁵ - (κ₁*κ₃*κ₁₄)₀ + (x + 2)*ψ₁¹²³ - 3*ψ₁*ψ₂ - x + 3
          sage: m1 = ([[]], {1:1})
          sage: m2 = ([[]], {})
          sage: p = KappaPsiPolynomial([m1, m2], [3, 4])
          sage: unicode_art(p)
          3*ψ₁ + 4
        r)�
UnicodeArtTrD)�sage.typeset.unicode_artrFrC)r�rFr.r.r/�
_unicode_art_�sz KappaPsiPolynomial._unicode_art_Tc
Csl|}tt|j��D]:}|j|\}}|D]}|r0|ddkr0d}|r0|ds0|��|r0|dr&qt|�D]
}||sBd}|�|�q5q	|r�d}|t|j�kr�|j|sa|j�|�|j�|�qH|j|}|d}		z	|j�||	�}	Wn	ty}Ynw|j||j|	7<|j�|	�|j�|	�qk|j|s�|j�|�|j�|�n|d7}|t|j�ksO|S)a�
        Remove trailing zeroes in kappa and l with psi[l]=0 and things with coeff=0
        and sum up again.

        TESTS::

          sage: from admcycles.admcycles import kppoly
          sage: kppoly([([[], [0, 1]], {})], [5]).consolidate()
          5*(kappa_2)_1
          sage: kppoly([([[0, 0], [0,1,0]], {})], [3]).consolidate()
          3*(kappa_2)_1
          sage: kppoly([([[], [0,1]], {})], [0]).consolidate()   # known bug
          0
        rCrTr)r3r9r�r`r2r�rOr*)
r��force�modifiedr?r�r��kaprtr5rAr.r.r/r!
sR��
��

��
	�zKappaPsiPolynomial.consolidateNr��Fr�)r�r�r��__doc__r�r�r|r�r�r�r�r�r�rr}rrr#r"r'r;rCrErHr!r.r.r.r/r��s.
!	



, r�cCsn|dkrd|d|t|�S|dkrtgg�Sdd�t|�D�}|ddgdg||<t|ifgdg�S)a�
    Returns the polynomial (kappa_index)_vertex

    INPUT:

    vertex : integer
      the vertex on which the kappa class is supported
    index : integer
      the index of the kappa class
    numvert : integer
      the total number of vertices

    EXAMPLES::

      sage: from admcycles.admcycles import kappacl
      sage: kappacl(0, 2, 4)
      (kappa_2)_0
      sage: kappacl(2, 1, 3)
      (kappa_1)_2
    rrMcSr<r.r.ror.r.r/r�br=zkappacl.<locals>.<listcomp>r)�	onekppolyr�r3)r�rOrr+r,�lir.r.r/rGs
rcCs(dd�t|�D�}t||difgdg�S)z�
    Return the polynomial (psi)_leg - must give total number of vertices

    EXAMPLES::

      sage: from admcycles.admcycles import psicl
      sage: psicl(1, 4)
      psi_1
    cSr<r.r.ror.r.r/r�qr=zpsicl.<locals>.<listcomp>r)r3r�)�legrrOr.r.r/�psiclgs
rQcCs tdd�t|�D�ifgdg�S)z�
    Return one as a kappa-psi polynomial

    INPUT:

    numvert : integer
      the number of vertices

    EXAMPLES::

      sage: from admcycles.admcycles import onekppoly
      sage: onekppoly(4)
      1
    cSr<r.r.)rQ�cntr.r.r/r��r=zonekppoly.<locals>.<listcomp>r)r�r3)rr.r.r/rNus rNc@s�eZdZdZd8dd�Zdd�Zd9dd	�Zd
d�Zd:d
d�Zdd�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zd8dd �Zd8d!d"�Zd;d$d%�Zd&d'�Zd(d)�Zd*d+�Zd;d,d-�Zd9d.d/�Zd<d0d1�Zd<d2d3�Zd4d5�Zd6d7�ZdS)=�
decstratuma�
    A tautological class given by a boundary stratum, decorated by a polynomial in
    kappa-classes on the vertices and psi-classes on the legs (i.e. half-edges
    and markings)

    The internal structure is as follows

    - ``gamma``:  underlying stgraph for the boundary stratum
    - ``kappa``: list of length gamma.num_verts() of lists of the form [3,0,2]
      meaning that this vertex carries kappa_1^3*kappa_3^2
    - ``psi``: dictionary, associating nonnegative integers to some legs, where
      psi[l]=3 means that there is a psi^3 at this leg

    We adopt the convention that: kappa_a = pi_*(psi_{n+1}^{a+1}), where
    pi is the universal curve over the moduli space, psi_{n+1} is the psi-class
    at the marking n+1 that is forgotten by pi.
    NcCs�|jdd�|_|durdd�t|���D�}|duri}|dur,t||fgdg�|_dSt|t�r8|��|_dS|t|���|_dS)NFrlcSr<r.r.ror.r.r/r��r=z'decstratum.__init__.<locals>.<listcomp>r)r|r�r3r7r�polyr�rN)r�r�r�r�rTr.r.r/r��s
zdecstratum.__init__cCr�r�)r�rTr�r.r.r/r��r�zdecstratum.__bool__FcCs(t�t�}|j�|�|_|j��|_|Sr�)rSr�r�r|rT)r�rmrWr.r.r/r|�s
zdecstratum.copycCs\|jjd\}}|��d\}}}td|d�}t�t|j||�|||�}t�||||t	�S)z�Returns number of automorphisms of underlying graph fixing decorations by kappa and psi-classes.
        Currently assumes that self has exaclty one nonzero term.rr)
rTr��gnr_listr3r#�num_of_stratum�Pixtongraphr�Zautom_countr)r�r�r�r+r,r;rM�numr.r.r/�automorphism_number�s
zdecstratum.automorphism_numberTcCs�|durddlm}|dd�|r|}|jjdd�}n	|jdd�}|j}|j|ddd�\}}	}
|��||_|j��|j�|
�|rH||	|
fS|S)	ao
        Rename the markings according to ``dic``.

        EXAMPLES::

          sage: from admcycles.stable_graph import StableGraph
          sage: from admcycles.admcycles import decstratum
          sage: g = StableGraph([0, 0], [[1, 3], [2, 4, 5, 6]], [(3, 4), (5, 6)])
          sage: D = decstratum(g, [[0,1], []], {1: 1})
          sage: D
          Graph :      [0, 0] [[1, 3], [2, 4, 5, 6]] [(3, 4), (5, 6)]
          Polynomial : (kappa_2)_0*psi_1
          sage: D.rename_legs({1: 2, 2: 1})
          Graph :      [0, 0] [[2, 3], [1, 4, 5, 6]] [(3, 4), (5, 6)]
          Polynomial : (kappa_2)_0*psi_2
        Nrr&r(zRthe rename argument in decstratum.rename_legs is deprecated (and actually ignored)Trl)r��return_dicts)r)r'r�r|r}r~rT)r�r�r�r�rZr'r�Z	new_gammar��markings_relabellingZlegs_relabellingr.r.r/r}�s

zdecstratum.rename_legscC� dt|j�ddt|j�S�Nz
Graph :      �
z
Polynomial : )r�r�rTr�r.r.r/r��� zdecstratum.__repr__cCs0ddlm}|d�||j�|d�||j�S)uJ
        TESTS::

          sage: from admcycles.stable_graph import StableGraph
          sage: from admcycles.admcycles import decstratum
          sage: g = StableGraph([0, 0], [[1, 3], [2, 4, 5, 6]], [(3, 4), (5, 6)])
          sage: D = decstratum(g, [[0,1], []], {1: 1})
          sage: unicode_art(D)
          Graph :
           ╭───╮
           │   │╭╮
           3   456
          ╭┴╮ ╭┴┴┴╮
          │0│ │0  │
          ╰┬╯ ╰┬──╯
           1   2
          <BLANKLINE>
          Polynomial : (κ₂)₀*ψ₁
        r)�unicode_artzGraph :z
Polynomial : )rGr`r�rT)r�r`r.r.r/rH�s$zdecstratum._unicode_art_cs�g}�j��}�fdd�t|�D�}�jD]6\�}}dd�t|�D��|D]}||�|||<q%��fdd�t|�D�}|d|9<|�|�q|S)Ncs(i|]}�jj|dd�D]}||�qqS�Fr��r�r)rQr=rtr�r.r/rp	r�z$decstratum.split.<locals>.<dictcomp>cSsg|]}i�qSr.r.r�r.r.r/r�
	r=z$decstratum.split.<locals>.<listcomp>cs(g|]}t�|g�|fgdg��qSrr�rr�)r��
psidiclistr.r/r�
	r�r)r�r7r3rTr�)r�r�rZlvdictr�r�rtZnewentryr.)r�rdr�r/�split	s
zdecstratum.splitcCr�r�r.r�r.r.r/r�	r�zdecstratum.__neg__cC�
|�|�Sr��r"r�r.r.r/r#	r�zdecstratum.__mul__cCs�ddlm}t|t�r|�|�St|t�rV|j��|j��kr$|�|�S|j��|j��kr4dkrDnnt	t|j|j
|j
d�g�S|��}|j�|�}||}|�
�St||�rd|��|g�|S|jdd�}|j
|9_
|S)a�
        TESTS::
            sage: from admcycles import TautologicalRing
            sage: P = TautologicalRing(1,2).psi(1)
            sage: P * next(iter(P._terms.values()))
            Graph :      [1] [[1, 2]] []
            Polynomial : psi_1^2
            sage: next(iter(P._terms.values())) * P
            Graph :      [1] [[1, 2]] []
            Polynomial : psi_1^2
        r�r�r�rTFrl)r�r�r��Hdecstratumr#rSr�r{r"r�rT�convert_to_prodtautclass�boundary_pullback�pushforwardr�r|)r�r�r��p1�p2r�r?r.r.r/r"	s"



$
zdecstratum.__rmul__cCs�t|�t|�ur
t�|j��|j��kr|�||�S|j��|j��kr*dkr7nn||j|j|jd�S|��}|j�|�}||�|�S)z�
        Return the result of the multiplication of the decstratum ``self``
        and the decstratum ``other`` in the tautological ring ``R``
        rri)	�typer�r�r{�multiplyrTrkrlrm)r�r��Rrnror.r.r/rq<	s$zdecstratum.multiplycCs0ddlm}|j��}|j��}|||�|g�S)a�
        Converts decstratum to TautologicalClass.

        EXAMPLES::

            sage: from admcycles.admcycles import decstratum, StableGraph
            sage: d = decstratum(StableGraph([1],[[1,2,3]],[(2,3)]),psi={1:1})
            sage: dt = d.to_tautological_class()
            sage: dt.parent()
            TautologicalRing(g=2, n=1, moduli='st') over Rational Field
        r�r�)r�r�r�r+r,)r�r�r+r,r.r.r/�to_tautological_classP	s

z decstratum.to_tautological_classcCst||||�Sr�)�converttoTautvect�r�r+r,r;r.r.r/�
toTautvecta	�zdecstratum.toTautvectcCstt||||�|||�Sr�)�Tautvecttobasisrurvr.r.r/�toTautbasisd	szdecstratum.toTautbasis�stcs�tt|jj�ddd�D]]}|jj|\��t|j���D]K�t��fdd�tt����D��}t�fdd�|jj�dd�D��}t|j�	��|j�
��t|��}|||krh|jj�|�|jj
�|�nqq|S)NrrCcs g|]}|d��|�qSrrr.r�)r�r=r.r/r�m	rmz/decstratum.dimension_filter.<locals>.<listcomp>csg|]
}|�vr�|�qSr.r.rs�r�r.r/r�n	r#Fr�)r3r9rTr�r�r7rErr r�num_legsrr`r�)r��modulir?Z	kappa_degZpsi_deg�socler.)r�r�r=r/�dimension_filterh	s$" ��zdecstratum.dimension_filtercCsXtt|jj�ddd�D]}|j�|�|j��|kr)|jj�|�|jj�|�q|S)NrrC)	r3r9rTr�r�r�r{r`r�)r��dmaxr?r.r.r/�
degree_capw	s�zdecstratum.degree_capcCsP|jdd�}tt|jj��D]}|j�|�|j��|kr#d|jj|<q|�	�S)NFrlr)
r|r3r9rTr�r�r�r{r�r!)r�r�r�r?r.r.r/�degree_part	s�zdecstratum.degree_partcC�|j��|Sr��rTr!r�r.r.r/r!�	�
zdecstratum.consolidatec
	s�t|dd�}d}|jD]i\}�}d}t|j���D]T}�fdd�|jj|dd�D�}g}	tt||��D]�|	�fd	d�t||��D�7}	q4t||	�t|j�	|�t|�|�kr^d}n|t
j|j�	|�||	|d
�9}q|||7}q|S)NT��DRpyrrcsg|]}��|d��qSr�rrsr|r.r/r��	r[z'decstratum.evaluate.<locals>.<listcomp>Fr�csg|]}�d�qSrrr.r��rAr.r/r��	r^��moduli_type)rrTr3r�r7rr9rEr rr#Z
socle_formula)
r�r~ZDRmoduli�answerr�r�r�r=ZpsilistZ	kappalistr.)rAr�r/�evaluate�	s$$ zdecstratum.evaluatec
s�|jdd�}|��tt|j�����|D�]��|j����|j���dkr�t|jj	�dd��dkr�|jj	�dd�}|�
��t|��t|j�
���}|rxt|�d}|�
|�|d}|j�|�}|jD]\}	�}
|�vrw��|�}|�|<qe|j��g�|j������|jD]
\}	�}
|	���q��n|j���}|j���d}
|j���tgg�}|jD]�\}	�}
dd	�|	D�}g|�<���}|jj	�dd�D]}|�|d�q�t||fg|
g�}|	����fd
d�|jj	�dd�D��tdd	�t��D��fgdg�}���d�}g}�D]}|�tt|d����qtgg�}tj|�D]C�|t��fd
d	�tt���D��t���fdd	�tt���D��|t�|t��fdd	�tt���D��d�||
d�7}�q)|dk�r�t���fdd	�tt���D��}��fdd��|t��fdd	��D��|7}|||7}q�||_|j��g�|��q|j��|�r�|�fdd�tt���D�fS|S)a?
        Return the decstratum corresponding to the pushforward under
        the map forgetting the ``markings``.

        The obtained ``decstratum`` has underlying stable graph the one obtained by
        forgetting and stabilizing. The algorithm currently works by forgetting one
        marking at a time.
        TrlrFr�r%rcSror�r.�rQrKr.r.r/r��	r[z4decstratum.forgetful_pushforward.<locals>.<listcomp>cs"i|]
}|�kr|��|d��qSr�rrs)r5r�r.r/rp�	r�z4decstratum.forgetful_pushforward.<locals>.<dictcomp>cSr<r.r.ror.r.r/r��	r=csg|]}t�|�|��qSr.rro��cvect�kappavr.r/r��	rxc�$g|]}t�|d���|�qSrrrro)r�rr=r.r/r��	rics$g|]}�|�||d�qSrrr.ror�r.r/r��	rir4cr�rrrro)r�rr=r.r/r��	rics8���}||d8<tdd�t��D�|fgdg�S)NrcSr<r.r.ror.r.r/r��	r=zJdecstratum.forgetful_pushforward.<locals>.psiminuspoly.<locals>.<listcomp>)r|rr3)rtZ	psivminus)r�psivr.r/�psiminuspoly�	s z6decstratum.forgetful_pushforward.<locals>.psiminuspolycs g|]}�|dkr�|��qSr�r.rs)r�r�r.r/r��	rmcrr.r.r�)�vertimr.r/rp�	r�)r|r�r2r3r�r7r�rr9rr�rZr�rz�leginversionrTr`�forget_markings�	stabilizer}rrr�r_r�rrrEr~)r�rMr�r�ZvlegsZvmarksZmprimerPZlegprimer�r�r�r+r,�newpoly�
trunckappaZtruncpsirt�trunckppolyZpsivpoly�a_mZcpossr6Zcurrpolyrr.)	r�r�r5rr�r�r�r=r�r/�forgetful_pushforward�	s�	
(


�

�

  
2
��4
�
" 

z decstratum.forgetful_pushforwardcs�|s|gS|rNt|jjdt|�d�}|jdd�}dd�|jjD�}|jjdd�D]}|D]}||vr<|||<|d7}q.q*|jji|dd�|j�|�n|}|d	}|dd
�}	g}
t	|j�
��D�]`�|j��}|j�|g7<|��|��t
gg�}|jD]i\�}
}dd���D�}tj|�D]U�d
d��D�}t��|�<|
��}t���fdd�t	t���D��||<|t
||fgdt���fdd�t	t���D��|t���fdd�t	t���D��g�}q�q�|j��t|jjd|d�}i�|jj�dd�D]G}|j��}|j��|�|j�|g7<|jd	g7_|j|d||gg7_|j||dfg7_|��|��|�|<�q	dd�|jj�dd�D��|jD]I\�}
}t|
��t|jj�dd���D]3}|
|d	k�r��qudd��D�gg}|
��}|�|�d||<�|t
||fg|g��|<�qu�qa|
t||d�g��fdd�|jj�dd�D�7}
qcg}|
D]}|�|�|	���q�|S)z�
        Return a list of :class:`decstratum` that corresponds to the pullback under
        the forgetful map which forget the markings in ``newmark``.
        rTrlcSsi|]
}|D]}||�qqSr.r.)rQrtr?r.r.r/rp	
r#z6decstratum.forgetful_pullback_list.<locals>.<dictcomp>Fr�r�rNcSsg|]}ttd|d���qS�rr�r2r3�rQr5r.r.r/r�-
rxz6decstratum.forgetful_pullback_list.<locals>.<listcomp>cSror�r.r�r.r.r/r�0
r[cs(g|]}|d��|�|�qSrrr.ro��bdsr�r=r.r/r�4
r�rCcs g|]}��|�|�qSr.r.ror�r.r/r�5
rmcs"g|]
}t��|�|��qSr.rror�r.r/r�6
r�cSsi|]}|tgg��qSr.rcrsr.r.r/rpM
r[cSror�r.r�r.r.r/r�T
r[rics0g|]}t�|�dkrt�|�|d��qS)rri)r9rSrs)�grl�polylr.r/r�[
s�)r.r�r/r|�_legsr�r�rTr}r3r7rJr~rr_r�r2rEr9rrr��_generar�rZr�r`rS�extend�forgetful_pullback_list)r��newmarkr�ZmlegZrnselfr�r�r?rZnextnewmarkZpartpullbackZgrvZpolyvr�r�Z	binomdistZ	kappa_newZpsi_new�newlegrtZnew_grrAr��dsr.)r�r�r�r�r=r/r��	s���

&0� ��

"$��z"decstratum.forgetful_pullback_listcCst|�||��Sr�)r�r�)r�r�r�r.r.r/�forgetful_pullbackd
r�zdecstratum.forgetful_pullbackc
s�g}�jD]V\}�}g}t�j���D]9����fdd�tt�jj���D�}|�tt�j�	��gt
tdt�jj��d��gg�|�g|d��q|dj|9_|�|�qt�j|�S)Ncs:i|]}�jj�|�vr|d��jj�|�qSrr�r�r�)rQ�lnum�r�r�r=r.r/rpn
s �z7decstratum.convert_to_prodtautclass.<locals>.<dictcomp>r�r�r�r)rTr3r�r7r9r�r�rSr1rr2�
prodtautclass)r��termsr�r�Zcurrtermr�r.r�r/rkh
s"���

�z#decstratum.convert_to_prodtautclasscsN�j����j����j�������fdd�tt�jj��D�}tt	|��S)Nc3s&�|]}����j�|�fVqdSr�)rTr�ro�r�r+r,r�r.r/rV{
s�$z&decstratum.gnr_list.<locals>.<genexpr>)
r�r+r,r{r3r9rTr�r2rZ)r�r)r.r�r/rUw
s



$zdecstratum.gnr_list�NNNrL)NTF�r{r�)r�r�r�rMr�r�r|rYr}r�rHrer�r#r"rqrtrwrzr�r�r�r!r�r�r�r�rkrUr.r.r.r/rS�s6


	!$





`
grSc@sleZdZdd�Zdd�Zdd�Zdd�Zd	d
�Zdd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dd�ZdS)�
HtautclasscCs
||_dSr��r�)r�r�r.r.r/r��
r�zHtautclass.__init__cCs t�t�}dd�|jD�|_|S)NcS�g|]}|jdd��qS�Frlr��rQZHdsr.r.r/r��
r[z#Htautclass.copy.<locals>.<listcomp>)r�r�r��r�rjr.r.r/r|�
s
zHtautclass.copycCr�r�r.r�r.r.r/r��
r�zHtautclass.__neg__cC�:|dkr|��S|��}|jdd�|jD�7_|��S)NrcSr�r�r�r�r.r.r/r��
r[z&Htautclass.__add__.<locals>.<listcomp>�r|r�r!�r�r�r?r.r.r/r��
�
zHtautclass.__add__cC�|dkr|S||SrDr.r�r.r.r/r�
�zHtautclass.__radd__cCs4|��}tt|j��D]}||j||j|<q|Sr�)r|r3r9r�r$r.r.r/r"�
szHtautclass.__rmul__cs2ddlm}t�|�rt�fdd�|jD��SdS)Nrrhcs$g|]}�j��D]}||�q	qSr.��_termsr�r rr.r/r��
riz&Htautclass.__mul__.<locals>.<listcomp>)r�r�r�rEr�)r�r�r�r.rr/r#�
s
�zHtautclass.__mul__cs"d��fdd�tt�j��D��S)N�

c3s�|]
}t�j|�VqdSr�)r�r�ror�r.r/rV�
s��z&Htautclass.__repr__.<locals>.<genexpr>)r0r3r9r�r�r.r�r/r��
s�zHtautclass.__repr__cCs&tt|j��D]	}|j|��q|Sr�)r3r9r�r!r�r.r.r/r!�
szHtautclass.consolidatecCsT|jstd��t|jdjj��g|jdjj��gg�}dd�|jD�}t||�S)NzCHtautclass does not know its graph, failed to convert to prodHclassrcS�g|]}|���qSr.)r
r�r.r.r/r��
r^z,Htautclass.to_prodHclass.<locals>.<listcomp>)r�r*r1rfr�r+rzr	�r��gamma0r�r.r.r/r�
s
,
zHtautclass.to_prodHclasscCs"|jstg�Stdd�|jD��S)Ncss�|]}|��VqdSr�)�quotient_pushforward�rQr�r.r.r/rV�
r.z2Htautclass.quotient_pushforward.<locals>.<genexpr>)r�r�rEr�r.r.r/r��
szHtautclass.quotient_pushforwardcsf|jst|�S|jdjj���|jdjj�t���}|�d�}td�||�	�}||}|�
�tg�}tdd�|j
��D��}��fdd�|D�}��fdd�|D��|j
��D]�}	t|	j�\��}
����fdd	�tt|���D�}|D]�}|�|����j��}
t�fd
d	���|djdd�D��|	j��ttt�����}��|\}}}}}�tgg�}|	jD]`\}�}|}d
d	�t|
�D�}tt|��D]#}|||||
|<|td���||
|���t||�9}qև��fdd��D�}|t����fdd	��D��9}|t||fg|g�7}q�||9}|j�t�|d��qzq\|S)Nrrcs��|]}|j��VqdSr�)r�r{r�r.r.r/rV�
r�z/Htautclass.quotient_pullback.<locals>.<genexpr>csi|]	}|t��|��qSr.)r�ro�r+r�r.r/rp�
ryz0Htautclass.quotient_pullback.<locals>.<dictcomp>csi|]
}|t��|d��qSr�)r�ror�r.r/rp�
r#cs$g|]}��|d�kr|�qSrrr.r�)�Hquotsr;�tir.r/r��
riz0Htautclass.quotient_pullback.<locals>.<listcomp>csg|]\}}��|����qSr.�rr�rQ�e0�e1)�newGrr.r/r��
rxFr�cSr<r.r.)rQ�ur.r.r/r��
r=csi|]}��|�|�qSr.r.rs)�diclinvr��tdiclr.r/rp�
rxcs*g|]}����|����|�qSr.r�rs)r�r�r�r�r.r/r��
r�ri)r�rrfr�r+r�rrSrr�r�r�rZr�r�r�r3r9r|r7rr�rYrsrrTrrrEr�rj)r�r��trivGg�deltadeg�push�pror�ZedgenumsZHstratar�ZtdicvZpreimsrAr�multiplicityZ
quotientgraphZinder�rrUr�r�r�ZnewcoeffZnewkappar=Znewpsir.)	r�r�r+r�r�r�r;r�r�r/�quotient_pullback�
sR

"

���
0 �zHtautclass.quotient_pullbackN)r�r�r�r�r|r�r�rr"r#r�r!rr�r�r.r.r.r/r��
s
	r�c@sXeZdZddd�Zddd�Zdd�Zd	d
�Zdd�Zd
d�Zdd�Z	dd�Z
dd�ZdS)rjNcCs\||_|durdd�t|j���D�}|duri}|dur)t||fgdg�|_dS||_dS)NcSr<r.r.ror.r.r/r�r=z(Hdecstratum.__init__.<locals>.<listcomp>r)rfr3r�r7rrT)r�rfr�r�rTr.r.r/r��
s
zHdecstratum.__init__TcCs*t�t�}|jj|d�|_|j��|_|Sr�)rjr�rfr|rT)r�rmrjr.r.r/r|
s
zHdecstratum.copycCr�r�r.r�r.r.r/r�r�zHdecstratum.__neg__cCs.t|t�r
|�|�S|��}|j|9_|Sr�)r�rSr#r|rTr�r.r.r/r"s


zHdecstratum.__rmul__cCs|j��}|j|j9_|Sr�)rfr
rT)r�r�r.r.r/r
s
zHdecstratum.to_decHstratumc)s�t|t��rh�jj��dkr�|j��}t|��jj����}�fdd�t	|d�D�}g}g}t	||d�D]�}||D]�}g}	g}
t
|j|j�}|sMq=t||�}|r�|d\��d}
|D].\����fdd��D�}��fdd��D�}z
|�||f�|
d7}
Wq^t
y�Yq^wt�}|jD]}���D]}|�|j||f�q�q�t|j����|�r�|	dd�t	|j���D�d	d��jj��D���fg7}	|
td�t|�9}
|
|
g7}
|sT|||	fg7}||
g7}q=q7tg�}t	t|��D�]n}||d�sq�||d}tgg�}t	t||d��D�]>}||d|\}�}}d
d�t	�jj���D��|D]}�|||g7<�q4dd�t	|j���D��	|D]}�	|||g7<�qQ|j���i}|j|d�}d
d�|��D�}�jj��D]}||�|d7<�q||j��D]}||||d7<�q�t��}|jdd�D] \}} ||dk�r�|dt|��t| ��||d9}�q�tgg�}!�jD]q\��
}"|jD]g\�}#}$��
fdd��
D�}%|#D]}|%�||d�|#||%||<�q�tdd�t	��D�|%fgdg�}&t���fdd�t	�jj���D��}'t���	fdd�t	|j���D��}(|!|"|$|&|'|(7}!�qܐq�|!||||9}!||!7}�q|j tt!||d�g�g7_ q�|SdS)Nrcs$g|]}t�jj���jj|��qSr.)r�rfr�r+r�rar�r.r/r�-riz'Hdecstratum.__mul__.<locals>.<listcomp>rcr�r.r.r�)r��dicvcurrr.r/rp@ryz'Hdecstratum.__mul__.<locals>.<dictcomp>cr�r.r.rs)rU�diclcurrr.r/rpArycSr�r�r.r�r.r.r/rpOrqcSrnr.r.rsr.r.r/rpPrqcSr<r.r.ror.r.r/r�gr=cSr<r.r.ror.r.r/r�jr=r�cSr�r�r.rsr.r.r/rprrqFr�rCcr�r.r.rs)�ldict1rr.r/rp�rycSr<r.r.ror.r.r/r��r=cr)cr)crrrrr�rr.r/r��r#�=Hdecstratum.__mul__.<locals>.<listcomp>.<listcomp>.<listcomp>rr�)rr�preim1r=r	r/r��r
�2Hdecstratum.__mul__.<locals>.<listcomp>.<listcomp>rr�)rrr�rr/r��r
cr)cr)crrrrr�rr.r/r��r#r�rr�)rr�preim2r=r	r/r��r
r�rr�)rrr�rr/r��r
ri)"r�rSrfr�r{rr<rrUr3r�rsr�r*rZr�r^r�r\�issubsetr7r�r9r�rr�rNr�rQrTrrr�rj))r�r��maxdegZmindegZGgrdegenerationsr�Zmultiplicityvectorr�ZGamma3Z
currentdegZcurrentmultiplicityZotstructures�AutGrr�ZdicvnewZdiclnewZcoveredlegsr+rtr�r>ZgammaresultpolyZcount2Zvdict1Zvdict2Zldict2r=ZquotdiclZ	quotgraphZnumpreim�
excesspolyr�r�r�coeff1r�coeff2rrZ
kappapoly1Z
kappapoly2r.)rUr�r�r�rrr�rr�r�rr�r/r#!s�

�
��
��+

(�
$ ��� �zHdecstratum.__mul__cCr\r])r�rfrTr�r.r.r/r��r_zHdecstratum.__repr__cCr�r�r�r�r.r.r/r!�r�zHdecstratum.consolidatecs��jj��}i}i�i}�jj|�|d�}dd�t|���D�}t�jj���D]
}||||g7<q(��fdd��D�}tgg�}�jD]s\}	}
}g}|}
i}t|���D]'}g}||D]	}t	||	|�}qa||g7}|
t
|�t||�t|�9}
qY|
D]$}|�
||d�|
||||<|
t
d��jj|d|
|9}
q�|
t|���9}
|t||fg|
g�7}qHtt||d�g�S)	N)r�rrUcSr<r.r.ror.r.r/r��r=z4Hdecstratum.quotient_pushforward.<locals>.<listcomp>csi|]}|�j��|��qSr.)rfrSr��Zqdicvinvr�r.r/rp�rxz4Hdecstratum.quotient_pushforward.<locals>.<dictcomp>rrri)rfr<rr�r3r7r�rrTrrr9rErr�rr�r�rS)r��GordZqdicvZqdiclrZ	preimlistr=r�rr�r�r�ZkappanewZcoeffnewZpsinewrZ	kappatemprtr.r�r/r��s4

" &z Hdecstratum.quotient_pushforwardr�r�)r�r�r�r�r|r�r"r
r#r�r!r�r.r.r.r/rj�
s


	trjcCs8|r|ddkr|��|r|ddksdSdSdSdS)a�
    Remove the trailing zeroes t the end of l.

    EXAMPLES::

        sage: from admcycles.admcycles import remove_trailing_zeros
        sage: l = [0, 1, 0, 0]
        sage: remove_trailing_zeros(l)
        sage: l
        [0, 1]
        sage: remove_trailing_zeros(l)
        sage: l
        [0, 1]

        sage: l = [0, 0]
        sage: remove_trailing_zeros(l)
        sage: l
        []
        sage: remove_trailing_zeros(l)
        sage: l
        []
    rCrN)r`�rtr.r.r/�remove_trailing_zeros�s �r�cs|t|�t|�kr|t|�t|�dg�n|�t|�t|�kr.|t|�t|�dg�n|���fdd�tt���D�S)Nrcsg|]
}�|�|�qSr.r.ro�ZaprimeZbprimer.r/r��r#zkappaadd.<locals>.<listcomp>)r9r3)rr6r.r�r/r�src		s"g}g}td�j���D]'�|��j�dfd�|���fdd�td�j�df��d�D��qdd�|D�}g}i}�j��}td�j���D�]8}td�j���D]
��j�|fdkrdnqW�jd|fdkr�|�d�t�jd|f���j�|f��dkr��j�|fd|�jd|f<�jd|fdk�r��j�|fddkr�|�d||dg7<|�||df��j�|f��dkrۈj�|fd||<�j�|f��dkr�j�|fd||d<|d7}�j�|fddk�r��j���dk�rtd�t�j�t�d�j���D]}�j||fdk�r.n�q |�d|g7<||d|dg7<|�||df��j�|f��dk�rh�j�|fd||<�j||f��dk�r��j||fd||d<|d7}qLtt	|||�||d�S)	a;
    Converts a Pixton-style Graph (matrix with univariate-Polynomial entries) into a decstratum.

    Assume that markings on Graph are called 1, 2, 3, ..., n.

    The function :func:`Pixtongraph` provides the conversion in the other direction.

    EXAMPLES::

        sage: from admcycles.DR.graph import Graph, R, X
        sage: from admcycles.admcycles import Graphtodecstratum
        sage: G = Graph(matrix(R, 3, 2, [-1, 0, 1, 1, X + 2, 1]))
        sage: Graphtodecstratum(G)
        Graph :      [1, 2] [[2], [3]] [(2, 3)]
        Polynomial : (kappa_1)_1
    rrcsg|]}�j�df|�qSr�)r�r��r<r?r.r/r�rxz%Graphtodecstratum.<locals>.<listcomp>cSr<r.r.ror.r.r/r�r=rMZ	Attentionr�)
r3r��nrowsr��degree�ncolsrr�rSr1)	r<rr�rr�r�ZlegnamerArir.r�r/�Graphtodecstratum�sZ4
�  
��r��	admcycleszEhttps://gitlab.com/modulispaces/relations-database/-/raw/master/data/zJhttps://modulispaces.gitlab.io/relations-database/generating_indices_filesZADMCYCLES_CACHE_DIR�)�	directory�url�remote_database_list�env_varrJ�filenamer{cs��dkrtd��|s$�d�d�td�ks$�dks�dkr$�dks�|dur,�dk}|dkr2d	}|d
kr8d}tj���dt�d	d
�|d�����dkrjtjtt��	��
��g����f�R�tt��	���St�����fdd�t����D��}�tt|�	���}|�
�|�|��	~�	���	��}	�	fdd�|	D���fdd�t�	�	��D���fdd�tt���D��tt|	��D]�t��	fdd��D�����<q�t��fdd�t�	�	��D�������S�dkr�td��t��d�d��d	�}
t|
�}d}t|d�}
g�d}||k�rTt|
tt�t|
�|f�d�d��ttd�d����ggdd�}|��|k�rK��|�|}
|��}|d7}||k�s�S)a
    Return the indices of a basis of `R^r(\bar M_{g,n})` in terms of the standard list of generators.

    This function assumes that the generalized Faber-Zagier relations [PPZ15]_
    are a complete set of relations. For most parameters this is computed by
    using the FZ-relations. However, if r is greater than half the dimension of
    \bar M_{g,n} and all cohomology is tautological, we rather compute a
    generating set using Poincare duality and the intersection pairing


    INPUT:

    FZ : bool (default: True)
      Whether FZ relations are used to compute the basis. If False (only for moduli='st'),
      instead compute basis by pairing matrix from opposite degree.

    FZmethod : string (default: None)
      Which method is to be used for computing FZ relations, the options are '3spin' and 'newrels'.
      If no method is supplied we use the 3-spin formula when ``r`` < 3 and
      the new relation method otherwise.

    moduli : string (default: 'st')
      If instead of 'st' one of 'ct', 'rt' or 'sm' is given, compute a basis for the tautological
      ring of the corresponding open subset of `\bar M_{g,n}`.

    EXAMPLES::

        sage: from admcycles import generating_indices
        sage: generating_indices(1, 2, 1)
        [0, 1]
        sage: generating_indices(1, 2, 1, FZ=False)
        [0, 1]
        sage: generating_indices(1, 2, 1, moduli='ct')
        [0]
        sage: generating_indices(1, 1, 1, moduli='ct')
        []

    TESTS::

        sage: from admcycles import generating_indices
        sage: generating_indices(9, 0, 3, FZmethod='3spin', moduli='sm')
        [0, 1, 2]
        sage: generating_indices(9, 0, 3, FZmethod='newrels', moduli='sm')
        [0, 1, 2]

    We do the same as above, but we avoid the use of any chached results.

        sage: from admcycles import generating_indices
        sage: generating_indices.f(1, 2, 1)
        [0, 1]
        sage: generating_indices.f(1, 2, 1, FZ=False)
        [0, 1]
        sage: generating_indices.f(1, 2, 1, moduli='ct')
        [0]
        sage: generating_indices.f(1, 1, 1, moduli='ct')
        []

    Test the oneline database::

        sage: from admcycles import generating_indices
        sage: from tempfile import mkdtemp
        sage: from shutil import rmtree
        sage: import os
        sage: import pickle
        sage: generating_indices.set_online_lookup(True)
        sage: filename = "generating_indices_0_3_0_st.pkl"
        sage: tmpdir = mkdtemp()
        sage: filename_with_path = os.path.join(tmpdir, filename)
        sage: generating_indices._FileCachedFunction__download(filename, filename_with_path)  # optional - internet
        sage: f = open(filename_with_path, "rb")  # optional - internet
        sage: pickle.load(f)  # optional - internet
        [0]
        sage: rmtree(tmpdir)
    �tlz6generating_indices not implemented for treelike curvesr%rMr�NZ3spinTZnewrelsFrr�)Zsymmr�Zusespincs<g|]}tj��|���ttd�d��t�dd�d��qS)rTr�r�)r#� convert_vector_to_monomial_basis�rowr[r3rro)r+r~r,r;�relr.r/r��s
 �

�z&generating_indices.<locals>.<listcomp>csg|]
}���|d�qSrr�r�ro)�reordrelconvr.r/r��r#crYr.r.ro)�nongensr.r/r��r[cs&i|]}�|ttt��|di��qSrr)rrr9r��r�r.r/rp�r�z&generating_indices.<locals>.<dictcomp>cs&g|]}�����|df�qSrrr�r�)r?rr.r/r��r�crbr.r.ro)�gtobr.r/r��r^r{zQgenerating indices via pairing only implemented for whole moduli of stable curves��	subdivide)�NotImplementedErrorrr#Zrels_matrixrr��genstobasis�	set_cacher2r��basisr3r�reverse�matrix_from_columns�
echelonize�pivotsr9r�generating_indicesr�pairing_submatrixr[�rankr�)r+r,r;ZFZZFZmethodr~Z
spinmethodZrelconvZreverseindicesZreordnongensZ
gencompdegZmaxrankZcurrrankr�r>ZMnewr.)
r+r�rr?r~r,rr;r�rr/r1sjR8*
�
"(�

"��

�rcs|ttt�|�td�d�g�}|jdj���ttddt	|jdjj
������t�
����}g�|dus7|r@ttt	|���}n|}|D]!}|tt||�g�}|jr^�|����g7�qD�td�g7�qD|sj�St������t����fdd�t����D��}	|	t��}
|
d|
kr�tdtt	|
���ntd	t�|j|jf��td
t|
��|dur��S�fdd�|D�S)a�
    TESTS::

        We test that the function works correctly if the product Hbar * tautclass(...) is empty for some indices.

        sage: from admcycles.admcycles import HurData, Hintnumbers
        sage: G = CyclicPermutationGroup(2)
        sage: g = G.gen()
        sage: e = G.one()
        sage: dat = HurData(G, [g, e, g, e])
        sage: Hintnumbers(0, dat)
        [4, 1, 2, 2, 1, 2, 2, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
    rrirNcs"g|]
}t���|������qSr.�r#r�r�ro)r��dimensr+�markinsr.r/r��r�zHintnumbers.<locals>.<listcomp>rMz7Intersection numbers are consistent, number of checks: z(Intersection numbers not consistent for zrelcheck = crbr.r.r�)�
intnumbersr.r/r��r^)r�rjrrNr�rfr�r[r3r9r�rzr#�
all_stratar2r�r�r�r�r�	FZ_matrixrr�rr�r�r<rt)r+�datr8�
redundancy�Hbar�strataZ
effindicesr?r�MconvZrelcheckr.)r�rr+rrr/�Hintnumbers�s2$$r�pullc
sdt||�����}t�j���}|durttd|d��}t|�}t|���fdd�t|�D���fdd��D�}	|j�	�dkr^t|�|krJt
g�St
tt|gttd|d��gg��g�St
|t|�dd|dt|�|�s~tdt||f�d	�d
}
z-t||f}|D]"}t|��t|��r�t|�t|�}
t||�}|�t|
��}d}
q�Wn	ty�Ynw|dk�r|
�sttt||�td�d
�g���fdd�}ddlm}|||�}|jd|d||||d�}||ftvr�it||f<|t||fttd|d��<t|�|k�rt|||d
||�}|dk�r{|
�s{ddlm}|||�}tt|gttd|d��gg�tt|gttd|d��gg�d||fid�gg�g���fdd�}�fdd�}|jd|d|||||d�}|j �d
d�}|
�s�||ftv�r�it||f<t|�t||ft|�<|�r�|j |	d
d�}|�!d|dt|�|�S|S)a�
    Identifies the (pushforward of the) fundamental class of \bar H_{g,dat} in
    terms of tautological classes.

    INPUT:

    - ``g``  -- integer; genus of the curve C of the cover C -> D

    - ``dat`` -- HurwitzData; ramification data of the cover C -> D

    - ``method`` -- string (default: `'pull'`); method of computation

      method='pull' means we pull back to the boundary strata and recursively
      identify the result, then use linear algebra to restrict the class of \bar H
      to an affine subvectorspace (the corresponding vector space is the
      intersection of the kernels of the above pullback maps), then we use
      intersections with kappa,psi-classes to get additional information.
      If this is not sufficient, return instead information about this affine
      subvectorspace.

      method='pair' means we compute all intersection pairings of \bar H with a
      generating set of the complementary degree and use this to reconstruct the
      class.

    - ``vecout`` -- bool (default: `False`); return a coefficient-list with respect
      to the corresponding list of generators tautgens(g,n,r).
      NOTE: if vecout=True and markings is not the full list of markings 1,..,n, it
      will return a vector for the space with smaller number of markings, where the
      markings are renamed in an order-preserving way.

    - ``redundancy`` -- bool (default: `False`); compute pairings with all possible
      generators of complementary dimension (not only a generating set) and use the
      redundant intersections to check consistency of the result; only valid in case
      method='pair'.

    - ``markings`` -- list (default: `None`); return the class obtained by the
      fundamental class of the Hurwitz space by forgetting all points not in
      markings; for markings = None, return class without forgetting any points.

    EXAMPLES::

      sage: from admcycles.admcycles import trivGgraph, HurData, Hidentify
      sage: G = PermutationGroup([(1, 2)])
      sage: H = HurData(G, [G[1], G[1]])
      sage: t = Hidentify(2, H, markings=[]); t  # Bielliptic locus in \Mbar_2
      Graph :      [2] [[]] []
      Polynomial : 30*(kappa_1)_0
      <BLANKLINE>
      Graph :      [1, 1] [[2], [3]] [(2, 3)]
      Polynomial : -9

    Check that pair and pull methods are compatible::

      sage: from admcycles.admcycles import Hdatabase
      sage: Hdatabase.clear() # remove the cached results from the previous computation
      sage: t2 = Hidentify(2, H, markings=[], method='pair')
      sage: t == t2
      True

      sage: G = PermutationGroup([(1, 2, 3)])
      sage: H = HurData(G, [G[1]])
      sage: t = Hidentify(2, H, markings=[]); t.is_zero()  # corresponding space is empty
      True

    TESTS::

      sage: G = PermutationGroup([(1, 2)])
      sage: H = HurData(G, [G[1], G[1]])
      sage: Hidentify(2, H, markings=[2], vecout=True)
      (60, -21, 66, -123, -9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
      sage: Hdatabase.clear() # remove the cached results from the previous computation
      sage: Hidentify(2, H, markings=[2], vecout=True, method='pair')
      (60, -21, 66, -123, -9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    Nrc�i|]	}|d�|�qSrrr.ro��msortedr.r/rpH
ryzHidentify.<locals>.<dictcomp>cr�r.r.r�)�markingdictionaryr.r/rpI
r�rMr%zCareful, Hurwitz cycle z might not be tautological!
FT�pairrics"�|}|jstd�S|����SrD)r�rr�r�)rr)rr.r/�pairfh
szHidentify.<locals>.pairfrs)Zpairfunction�checkrrcs��|���Sr�)�gamma0_pullback�toprodtautclass�r���bar_Hr.r/�pullfun}
rxzHidentify.<locals>.pullfuncs�|��Sr��r�)r�r��clr(r.r/�kpfun�
rHzHidentify.<locals>.kpfun)ZpullfunctionZkappapsifunctionr$r�)"rr�r9r�rzr2r3rGr<rr�rSr1�
cohom_is_tautr�r��	HdatabaserZr�rr�rYr�rjrNr�r��identify_classr[�	Hidentifyr	rr}r)r+r�method�vecoutrrMr;r,r�Zinvmarkingdictionary�found�HdbrN�forgottenmarksr�r#r�rrr*r-Zrnresultr.)rr)r!r r/r1�sx
K((���
 
&��"r1c	s�t||��}t�|�ttd|d�����fdd�|D�}t|�}�durRtd|�}t||d�}	|	D]�|s<���dkrKt	|gt
||���ggdd�}q2|��|S��fdd�|D�}
t|
���}|��|S)	a0
    Compute matrix representing pullback of basis of the tautological ring
    of Mbar_g,n in degree d under boundary pullbacks.

    If bdry is given (as a StableGraph with exactly one edge) it computes
    the matrix whose columns are the pullback of our preferred basis to the
    divisor bdry, identified in the (tensor product) Tautbasis.
    If bdry=None, concatenate all matrices for all possible boundary
    divisors (in their order inside list_strata(g,n,1)).

    If additionally irrbdry=False, omit the pullback to the irreducible
    boundary (since there computations get more complicated).

    EXAMPLES::

        sage: from admcycles.admcycles import StableGraph, pullback_matrix, list_strata
        sage: pullback_matrix(2, 0, 1)
        [ 1 -2]
        [ 0  4]
        [ 1 -2]
        [ 1 -2]
        sage: L = list_strata(2,0,1); L
        [[1] [[1, 2]] [(1, 2)], [1, 1] [[1], [2]] [(1, 2)]]
        sage: pullback_matrix(2, 0, 1, L[0])
        [ 1 -2]
        [ 0  4]
        sage: pullback_matrix(2, 0, 1, L[1])
        [ 1 -2]
        [ 1 -2]
    rc�g|]}t�|��qSr.�r�ro)rr.r/r��
r[z#pullback_matrix.<locals>.<listcomp>NrFrcsg|]}��|���d��qSr�)rl�totensorTautbasis)rQr,)�bdryr�r.r/r��
rx)
rr#rr[r3r9rr6r7r�pullback_matrixr~�	transpose)r+r,r�r:�irrbdry�
genindicesr��ngensr�Zbdrydiv�	pullbacksr.)r:r�rr/r;�
s" 
�r;csxddlm}t|||�}|||��|���fdd�|D��tt||d|d||��}�fdd�|D�}t|�|fS)a=
    Computes the matrix B whose columns are the intersection numbers of our preferred
    generating_indices(g,n,d) with the list kppolynomials of kappa-psi-polynomials of
    opposite degree. Returns the tuple (B,kppolynomials), where the latter are
    class:`TautologicalClass`.

    TESTS::

      sage: from admcycles.admcycles import kpintersection_matrix
      sage: kpintersection_matrix(0,5,1)[0]
      [5 3 3 3 3]
      [3 1 2 2 2]
      [3 2 1 2 2]
      [3 2 2 1 2]
      [3 2 2 2 1]
      [3 2 2 2 2]
      sage: kpintersection_matrix(0,5,2)[0]
      [1]
    rrscrbr.r.ro)�tgr.r/r��
r^z)kpintersection_matrix.<locals>.<listcomp>r%csg|]��fdd��D��qS)csg|]}|����qSr.r+)rQr��sr.r/r��
r[z4kpintersection_matrix.<locals>.<listcomp>.<listcomp>r.r�rrBr/r��
rx)r�r�r�
generatorsr2�
kappapsipolysr)r+r,r�r�r>Z
kppolynomials�Br.)r�rAr/�kpintersection_matrix�
s rGc@s�eZdZdZd,dd�Zdd�Zdd�Zd	d
�Zd-dd�Zd
d�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd#d$�Zd%d&�Zd'd(�Zd.d*d+�ZdS)/r�a�
    A tautological class on the product of several spaces \bar M_{g_i, n_i},
    which correspond to the vertices of a stable graph.

    One way to construct such a tautological class is to pull back an other
    tautological class under a boundary gluing map.

    Internally, the product class is stored as a list ``self.terms``, where
    each entry is of the form ``[ds(0),ds(1), ..., ds(m)]``, where ``ds(j)``
    are decstratums.

    Be careful that the marking-names on the ``ds(j)`` are 1,2,3, ...
    corresponding to legs 0,1,2, ... in gamma.legs(j).
    If argument prodtaut is given, it is a list (of length gamma.num_verts())
    of tautclasses with correct leg names and this should produce the
    prodtautclass given as pushforward of the product of these classes that is,
    ``self.terms`` is the list of all possible choices of a decstratum from the
    various factors.
    Nc	s�|jdd��_|dur|�_dS|durAg}|D]}z|�|j�Wqty3|�|j���Yqwdd�tj|�D��_dS�fdd�t	�j�
��D�g�_dS)NFrlcS�g|]	}dd�|D��qS)cSr�r.r��rQr�r.r.r/r�r^z5prodtautclass.__init__.<locals>.<listcomp>.<listcomp>r.r�r.r.r/r�ryz*prodtautclass.__init__.<locals>.<listcomp>cs>g|]}tt�j�|�gttd�j�|�d��gg���qSrr)rSr!r�rr2r3r}ror�r.r/r�	s��
�)r|r�r�r�rr�r�r_r�r3r7)r�r�r��protautZdeclistsr�r.r�r/r��
s
�
�zprodtautclass.__init__cCs(t�t�}|j|_dd�|jD�|_|S)NcSrH)cSr�r.r�rIr.r.r/r�r^z1prodtautclass.copy.<locals>.<listcomp>.<listcomp>r.r�r.r.r/r�ryz&prodtautclass.copy.<locals>.<listcomp>)r�r�r�r�r�r.r.r/r|s
zprodtautclass.copycCs"ddlm}||j��|j���S)a�
        Return the target tautological ring of the gluing map pushforward.

        EXAMPLES::

            sage: from admcycles.admcycles import prodtautclass, StableGraph
            sage: H = StableGraph([2],[[1,2,4]],[])
            sage: b = prodtautclass(H)
            sage: b._tautological_ring()
            TautologicalRing(g=2, n=(1, 2, 4), moduli='st') over Rational Field
        rrs)r�r�r�r+rz)r�r�r.r.r/�_tautological_ringsz prodtautclass._tautological_ringcs*ddlm���fdd�t�j���D�S)zC
        Return the list of factors of the tensor product.
        rrscs&g|]}��j�|��j�|���qSr.)r�rr}r��r�r�r.r/r�&r�z)prodtautclass.factors.<locals>.<listcomp>)r�r�r3r�r7r�r.rLr/�factors!szprodtautclass.factorscsb|dur���}|��}�jD]�}t�j��dg�d}g}g}�j��}tdd�|D��}t|�}	t	t
|��D]h�|�}
|
j}t
|�}|�|�����fdd�t	t
�jj
���D��|jD]\}
}|�|
<|d�|<|d7}qb|�fd	d
�|j
D�7}|�fdd
�|jD�7}|
j��}|���|�||�|	|9}	q9||t|||�|	d�7}q|S)
a
        Return the tautological class obtained by pushing forward under the gluing
        map associated to gamma.

        EXAMPLES::

            sage: from admcycles.admcycles import prodtautclass, StableGraph, psiclass, fundclass
            sage: G = StableGraph([0, 2], [[1, 2, 4, 3], [5]], [(3, 5)])
            sage: b = prodtautclass(G, protaut = [psiclass(4,0,4), fundclass(2,1)])
            sage: b.pushforward()
            Graph :      [0, 2] [[1, 2, 4, 3], [5]] [(3, 5)]
            Polynomial : psi_3
        Nrrcsr�r��r�r7�rQrCr.r.r/rVHr�z,prodtautclass.pushforward.<locals>.<genexpr>cs"i|]
}|d�jj�|�qSrrr�r��r?r�r.r/rpTr�z-prodtautclass.pushforward.<locals>.<dictcomp>rMc�g|]}�fdd�|D��qS)crbr.r.rs��	renamedicr.r/r�Zr^z8prodtautclass.pushforward.<locals>.<listcomp>.<listcomp>r.�rQrLrRr.r/r�Zrxz-prodtautclass.pushforward.<locals>.<listcomp>c� g|]\}}�|�|f�qSr.r.r�rRr.r/r�[rmri)rKr�r�r.r�r�r�rErNr3r9r�rr�r�rTr|r}rr!)r�rrr�r��maxlegrrr�rrTrCr�rr�r��grpolyr.)r?rSr�r/rm-s8

$



zprodtautclass.pushforwardc

sh|j�dd��jdd�D��|D]}�||�|�q����g�t����D]-���t�fdd���D��fdd���D�����fdd��jdd�D�dd	��q(t�g�}��fd
d�t����D�}t����D]���j	|���j
dd�qo|jD]-����fdd�t����D�}d
d�|D�}tj
dd�|D��D]
}	|j�t|	��q�q�|S)a+
        Given a stgraph gamma0 and (dicv,dicl) a morphism from self.gamma to gamma0 (i.e.
        self.gamma is a specialization of gamma0), it returns the prodtautclass on gamma0
        obtained by the partial pushforward along corresponding gluing maps.

        Notice that in this version, one needs to 'unedge' the edges of gamma0 and also
        the corresponding edges in self.gamma; otherwise the method rename_legs will not
        function.

        INPUT:

        - gamma0 (StableGraph): the graph obtained by some contraction of edges
          of self.gamma
        - dicv (dict): a dictionary describing the map of vertice of self.gamma
          to vertices gamma0
        - dicl (dict): a dictionary describing the map of legs of gamma0 to
          self.gamma

        EXAMPLES::

            sage: from admcycles.admcycles import StableGraph, prodtautclass, decstratum
            sage: G = StableGraph([2,0],[[2,3,4],[1,5,6]],[(3,5)])
            sage: G1 = StableGraph([1,1],[[2,10],[1,3,11]],[(10,11)])
            sage: G2 = StableGraph([0],[[1,2,3]],[])
            sage: d1 = decstratum(G1, [[], [0,1]], {1: 1})
            sage: d2 = decstratum(G2)
            sage: E = prodtautclass(G, [[d1, d2]])
            sage: G0 = StableGraph([2],[[1,2,3,4]],[])
            sage: E.partial_pushforward(G0, {0:0,1:0}, {3: 6, 4: 4, 2: 2, 1: 1})
            Outer graph : [2] [[1, 2, 3, 4]] []
            Vertex 0 :
            Graph :      [1, 1, 0] [[9, 12], [2, 4, 13], [1, 11, 3]] [(9, 11), (12, 13)]
            Polynomial : (kappa_2)_1*psi_2



        cSr<r.r.r�r.r.r/r��r=z5prodtautclass.partial_pushforward.<locals>.<listcomp>Fr�c�g|]}��|��qSr.)rr�r'r.r/r��r�crXr.�rr�r'r.r/r��r�csTg|]&}��|d���vr��|d���vr|d�vs|d�vs|�qSr�r�r�)r��preimv�usedlegsr=r.r/r��s��
�

�Trlcs,g|]����fdd�t�����D��qS)cs(i|]}��j�dd�||d�qS)Fr�rrYr�)rUr�r=r.r/rp�r�[email protected]_pushforward.<locals>.<listcomp>.<dictcomp>)r3r}r�)rUr�rr/r���$�)�shift�tidyupcs.g|]}t�|�fdd��|D�g��qS)crbr.r.ro�r�r.r/r��r^[email protected]_pushforward.<locals>.<listcomp>.<listcomp>)r�r�)�preimgrrZr�r.r/r���.cSr�r.)rmrOr.r.r/r��r^cSsg|]}|j���qSr.r�)rQ�tpr.r.r/r��r�)r�rr�r�r3r7r1r�r�r}r/r�r_r�r2)
r�r�r�rUrr��rndicsZtempclassesZtemppush�combr.)rUr�r�r`rZr�r[r=r/�partial_pushforwardds.&L
�

� 
�z!prodtautclass.partial_pushforwardc
s�jjdd�}tdg���d�t|g�}�jD]�}i}dd��j��D�}i}g}t�j��dg�d}g�g��j��}	tdd	�|D��}
t	|
�}t
t|��D]��|�}|j}
t��}�|
jdd
�7�|�
�fdd�t
|t���D����fdd�t
�j����D��|
��D]\}}|�|<|d�|<|d
7}q���fdd�|
jD�7�|	�fdd�|
jD�7}	|�
����fdd�t
|t���D��|�fdd�t
|t���D�7}|j��}|���|�||
�||9}qRt��|	�}|j�t||||||��q|S)NFrlr.rcSrnr.r.rsr.r.r/rp�rqz.prodtautclass.toprodHclass.<locals>.<dictcomp>rcsr�r�rNrOr.r.r/rV�r�z-prodtautclass.toprodHclass.<locals>.<genexpr>r�csi|]}|��qSr.r.r��r?r.r/rp�rqcs&i|]}|d�jj�dd�|�qS)rFr�rbr�rPr.r/rp�r�rMcrQ)crbr.r.rsrRr.r/r��r^z9prodtautclass.toprodHclass.<locals>.<listcomp>.<listcomp>r.rTrRr.r/r��rxz.prodtautclass.toprodHclass.<locals>.<listcomp>crUr.r.r�rRr.r/r��rmcs:i|]}|�|t��fdd�tt�|��D��g�qS)csg|]}�ddf�qS�rrr.)rQ�counter)�trivgpelr.r/r��s�z9prodtautclass.toprodHclass.<locals>.<dictcomp>.<listcomp>)rr3r9r�)rr�trivgprir.r/rp�s
��cs0g|]����fdd�tt����D�g�qS)csi|]}��||d�qSrrr.)rQZlcount)rArr.r/rp�s
��z9prodtautclass.toprodHclass.<locals>.<listcomp>.<dictcomp>�r3r9r�rYr�r/r��s
��)r�r|r
r	r�r�r.r�rErNr3r9rrr}r�r�rTr}rr1r�r)r�r�r�r��dicv0�dicl0rrrVr�rrTrCr�rr�r�rWr�r.)rr?rrSr�rjrir/�toprodHclass�sR



" 
��


zprodtautclass.toprodHclasscs|t|j���fdd�t|j���D�}g�_|jD] }dd�|D�}tt|��D]
}|||||<q(�j�|�q|�S)Ncsg|]	}�jd|�qSr�r�rorr.r/r��s�z1prodtautclass.factor_pullback.<locals>.<listcomp>cSr�r.r�rIr.r.r/r��r^)r�r�r3r7r�r9r�)r��verticesZprodclZdefaulttermsr��newtermrAr.rr/�factor_pullback�s

�
zprodtautclass.factor_pullbackcCr�r�r.r�r.r.r/r��r�zprodtautclass.__neg__cCr�)NrcSrH)cSr�r.r�rIr.r.r/r��r^z4prodtautclass.__add__.<locals>.<listcomp>.<listcomp>r.r�r.r.r/r��ryz)prodtautclass.__add__.<locals>.<listcomp>r�r�r.r.r/r��r�zprodtautclass.__add__cCr�rDr.r�r.r.r/r�r�zprodtautclass.__radd__cCs>|dkr|St|t�r|j|jkrtd��|j|j7_|S)Nrz0summing two prodtautclasses on different graphs!)r�r�r�r*r�r�r.r.r/�__iadd__szprodtautclass.__iadd__cCrfr�rgr�r.r.r/r#r�zprodtautclass.__mul__cCs<t|t�r|�|�j|_|S|jD]
}|d|9<q|SrD)r�r�r"r�)r�r�r�r.r.r/�__imul__s

zprodtautclass.__imul__c
Cs�t|t�rU|j|jkrtd��t|jg�}|jD]:}|jD]4}g}t|���D]\}}|�t||�	|||�j
����q'tj
|�D]
}|t|jt|�g�7}qCqq|S|��}	|	jD]
}
||
d|
d<q\|	S)Nz1product of two prodtautclass on different graphs!r)r�r�r�r*r�rHrMr�r2rqr�r�r_r�r|)r�r�r��T1�T2Zvertextautclr=ZRfac�choicer?r�r.r.r/r"s$


&��
zprodtautclass.__rmul__cCs&|jD]}|D]}|��qq|��Sr�)r�r�r!)r�r�rCr.r.r/r�-s


�zprodtautclass.dimension_filtercCsXttt|j���}|��|D]}|j|D]}t|jj�dkr(|j�|�nqq|SrD)r2r3r9r�r
rTr�r`)r�Zrevranger?rCr.r.r/r!3s��zprodtautclass.consolidatecCs�dt|j�d}t|jdd�d�}tt|��D]%}tt||��D]}|dt|�dt|||�d7}q"|d7}q|�d�S)	N�Outer graph : r^cSsdd�|D�S)NcSsg|]}|j�qSr.r'ryr.r.r/r�?rqz<prodtautclass.__repr__.<locals>.<lambda>.<locals>.<listcomp>r.r�r.r.r/�<lambda>?sz(prodtautclass.__repr__.<locals>.<lambda>rIzVertex z :
r�)r�r�rGr�r3r9�rstrip)r�rCr�r?rAr.r.r/r�=s*

zprodtautclass.__repr__cs$|j��}t|�|dkstd��tt|�������i�g}t|d�D]9}||��d}||���	�|}||���
|�D]}|||��}	|	dkr^|��|<|�|	�nqCq&ddl
m}
|
|j���|j�����������fdd�|jD��}|��dt|td��|S)a�
        Assuming that the prodtautclass is a product v_0 x ... x v_(s-1) of tautclasses v_i on the
        vertices, this returns the mth factor v_m assuming that otherfactors=[v_1, ..., v_(m-1), v_(m+1), ... v_(s-1)]
        is the list of factors on the vertices not equal to m.

        EXAMPLES::

          sage: from admcycles.admcycles import StableGraph, prodtautclass, psiclass, kappaclass, fundclass
          sage: Gamma = StableGraph([1,2,1],[[1,2],[3,4],[5]],[(2,3),(4,5)])
          sage: pt = prodtautclass(Gamma,protaut=[psiclass(1,1,2),kappaclass(2,2,2),fundclass(1,1)])
          sage: res = pt.factor_reconstruct(1,[psiclass(1,1,2),fundclass(1,1)])
          sage: res
          Graph :      [2] [[1, 2]] []
          Polynomial : (kappa_2)_0

        NOTE::

          This method works by computing intersection numbers in the other factors. This could be replaced
          with computing a basis in the tautological ring of these factors.
          In principle, it is also possible to reconstruct all factors v_i (up to scaling) just assuming
          that the prodtautclass is a pure tensor (product of pullbacks from factors).
        rzGotherfactors must have exactly one entry for each vertex not equal to mrrscs2g|]�t��fdd��D�����g��qS)cs g|]}�|�|���qSr.r+)rQ�oi)�othertestclassr�r.r/r�rrmz?prodtautclass.factor_reconstruct.<locals>.<listcomp>.<listcomp>rr��rrr5Zotherindicesr{r_r/r�rs2z4prodtautclass.factor_reconstruct.<locals>.<listcomp>)r�r7r9r*r2r3r��degree_listr�r rDr�r�r�r�rr}rEr��simplifyrr)r�r5ZotherfactorsrCZotherintersectionr?�rvZrvcomplement�tc�intnumr�r�r.r|r/�factor_reconstructFs.


�� z prodtautclass.factor_reconstructFc
Cs�|j��dkr1|j�d�}|j�d�}tttt|||���}|jD]
}||d�	|||�7}q!|S|j��dkr�|j�d�}|j�d�}|j�d�}	|j�d�}
d|d|}d|	d|
}t
d||�}
t||�}dd�t|
�D�}t|
|d�D]A}t
ttt|||��tt|	|
||���}|jD]"}|d�	|||�}|d�	|	|
||�}|t
|���t
|�7}q�|�|�q||dd�t|d|d�D�7}|r�tdd�|D��S|S|j��dkr�td	�dSdS)
NrrrMr%cS�g|]}ttdd��qSr��rrror.r.r/r��r[z3prodtautclass.totensorTautbasis.<locals>.<listcomp>cSr�r�r�ror.r.r/r��r[cSs<g|]}t|���D]}t|���D]}|||f�qq
qSr.)r3r�r�)rQr�r?rAr.r.r/r��s<zKtotensorTautbasis not yet implemented on graphs with more than two vertices)r�r7rr}rrr9rr�rzr.rDr3rr<r�r�)r�r;r3r+r,r�r�r7rgr8r�Zrmax1Zrmax2�rminrar�r��vec1�vec2r.r.r/r9{s@

(
 �zprodtautclass.totensorTautbasis�NNr�rL)r�r�r�rMr�r|rKrMrmrernrqr�r�rrrr#rsr"r�r!r�r�r9r.r.r.r/r��
s,

7F:

	5r�cCs�t|t�r�|��|dur|j��}|durt|j���}t|jj�dkrF|dur/t	d�dSt
ttj
||ttd|d��t|dd�d��S|durZ|j��}|durZ|j��|}tj
||ttd|d��t|dd�d�}ttd|d��}t
t|�}|j��}	|jD]E\}
}}|	tdd�|
D��t|���|kr�z|��}
Wnty�t}
Ynw|t
|
|tjt|j|
|�|||t|dd�d�|i�7}q�|SdS)	Nrz)Unable to identify r for empty decstratumrTr�r�cr�)c3r�rNr.r�r�r.r/rV�r�z/converttoTautvect.<locals>.<listcomp>.<genexpr>r�r�r.r�r/r��r�z%converttoTautvect.<locals>.<listcomp>)r�rSr�r�r+r9rzrTr�r�rrr#�
num_stratar[r3rr�r{rEr�r�rrVrW)r�r+r,r;r~Zpolydeg�lengthrMr�Zgraphdegreer�r�r�Zparer.r.r/ru�sD

.
(

&�����rucCsdg}t|���D]+}dtj|�|�}tt||��D]}||||tj|d7}q|�|�q	|g}|��D]<}|�|�}	dtjd}||vrW|||tj7}|�|gdd�t|	�D�|gdd�t|��|	d�D��q<|j	dd�D]�\}
}|�|
�}|�|�}
||
k�r,dtjd}|�
|
d�dkr�|�
|d�dkr�|||
tj7}|�
|d�dkr�|�
|
d�dkr�|||tj7}|�
|
d�dk�r
|�
|d�dk�r
||
||kr�|||
tj||tjd7}n|||tj||
tjd7}|�dgd	d�t|�D�|gd	d�t|��|d�D��qd
d�t|��d�D�}dtjd}|
|v�rN|||
tj7}|||d<dtjd}||v�ri|||tj7}|||
d<|�|�qt|���}t�
|�S)a�
    Return a Pixton-style graph given a stgraph ``G`` and data ``kappa`` and
    ``psi`` as in a :class:`KappaPsiPolynomial`.

    The function :func:`Graphtodecstratum` provides the conversion in the other direction.

    EXAMPLES::

        sage: from admcycles import StableGraph
        sage: from admcycles.admcycles import Pixtongraph, Graphtodecstratum
        sage: st = StableGraph([0, 2], [[1, 2, 4], [3, 5]], [(4, 5)])
        sage: G = Pixtongraph(st, [[], [0, 1]], {1: 1})
        sage: G
        [     -1       1       2       3       0]
        [      0   X + 1       1       0       1]
        [X^2 + 2       0       0       1       1]
        sage: ds = Graphtodecstratum(G)
        sage: assert ds.gamma.is_isomorphic(st)
    rCrrcS�g|]}d�qSr�r.ror.r.r/r��r=zPixtongraph.<locals>.<listcomp>Fr�rMcSr�r�r.ror.r.r/r��r=cSr�r�r.ror.r.r/r��r=)r3r7r#�Xrr9r�rzr�r�rrr<�Graph)r<r�r�Zfirstcolr=�entryri�columnsrt�vertr�r�r�r��colr�r.r.r/rW�sN 
D


  $&$D


rWcsd|d|dks|dks|t||t|��krtg�S|dkrHt||||d��t||||���s5���St���t���fdd�t��D��St	||||d�}t|�t|�ks^J||f��tt
t|d���tt|��D]}||dkr�||||7�qm�S)NrMrr�r{c3s8�|]}�|��s�|�tt�|di��VqdSrN)�is_zerorrro��Wr�Zreslenr.r/rVs�6z"Tautvecttobasis.<locals>.<genexpr>�r~)r rrry�op_subset_spacer�r9rEr3rr)r=r+r,r;r~�vecsr?r.r�r/rys"0�ryzChttps://modulispaces.gitlab.io/relations-database/genstobasis_files)r�r�r�r�Zpickle_wrapperscCsJ||||ftjvrtj|||d|d�n	t|||d|d�t||||d�S)a�
    Returns the list of vectors expressing the generators of `R^r(\bar M_{g,n})` in terms of the
    standard basis.

    INPUT:

    moduli : string (default: 'st')
        If instead of 'st' one of 'ct', 'rt' or 'sm' is given, compute a basis expression for the
        tautological ring of the corresponding open subset of `\bar M_{g,n}`.

    EXAMPLES::

        sage: from admcycles import TautologicalRing
        sage: from admcycles.admcycles import genstobasis
        sage: genstobasis(1, 1, 1)
        [(1), (1), (24)]
        sage: [t.evaluate() for t in TautologicalRing(1,1).generators(1)]
        [1/24, 1/24, 1]
        sage: genstobasis(2, 1, 1, moduli='ct')
        [(1, 0), (0, 1), (5/7, -5/7)]
        sage: genstobasis(9, 0, 3, moduli='sm')
        [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

    TESTS:

    Test the oneline database::

        sage: from admcycles import generating_indices
        sage: from tempfile import mkdtemp
        sage: from shutil import rmtree
        sage: import os
        sage: import pickle
        sage: genstobasis.set_online_lookup(True)
        sage: filename = "genstobasis_0_4_0_st.pkl"
        sage: tmpdir = mkdtemp()
        sage: filename_with_path = os.path.join(tmpdir, filename)
        sage: genstobasis._FileCachedFunction__download(filename, filename_with_path)  # optional - internet
        sage: f = open(filename_with_path, "rb")  # optional - internet
        sage: pickle.load(f)  # optional - internet
        [(1)]
        sage: rmtree(tmpdir)
    Tr�)rr_�fr)r+r,r;r~r.r.r/r&s9rcCs6ddlm}|dd�ddlm}||||��||�S)zc
    Deprecated. Use :func:`admcycles.tautological_ring.TautologicalRing.from_vector` instead.
    rr&r(zbTautv_to_tautclass is deprecated. Please use the from_vector method from TautologicalRing instead.rs)r)r'r�r��from_vector)r=r+r,r;r~r'r�r.r.r/�Tautv_to_tautclassfs
r�cCs4ddlm}|dd�ddlm}|||��||�S)zi
    Deprecated. Use :func:`admcycles.tautological_ring.TautologicalRing.from_basis_vector` instead.
    rr&r(zcTautvb_to_tautclass is deprecated. Please use the from_vector method from TautologicalRing instead.rs)r)r'r�r��from_basis_vector)r=r+r,r;r'r�r.r.r/�Tautvb_to_tautclassps
r�c@sreZdZdZdd�Zdd�Zdd�Zdd	�Zd
d�Zdd
�Z	dd�Z
dd�Zdd�Zddd�Z
dd�Zdd�ZdS)r	z�
    A sum of gluing pushforwards of pushforwards of fundamental classes of
    Hurwitz spaces under products of forgetful morphisms.

    This is all relative to a fixed stable graph gamma0.
    cCs|jdd�|_||_dS)NFrl)r|r�r�r�r.r.r/r��s
zprodHclass.__init__cCr�r�r.r�r.r.r/r��r�zprodHclass.__neg__cCsR|dkrt|�St|t�r%|j|jkr't|�}|jt|j�7_|��SdSdSrD)rr�r	r�r�r!r�r.r.r/r��s�zprodHclass.__add__cCr�rDr.r�r.r.r/r�r�zprodHclass.__radd__cCs>|dkr|St|t�r|j|jkr|j|j7_|Std��)Nrz'sum of prodHclasses on different graphs)r�r	r�r�r*r�r.r.r/rr�s�zprodHclass.__iadd__cCsLddlm}t||tf�r|�|�St|�}|jD]
}||d|d<q|S)Nrrhr)r�r�r�rSr"rr�)r�r�r�r?r�r.r.r/r#�s

zprodHclass.__mul__cs�ddlm}t||tf�re|j�|�}|��}tt|j�g�}|j	D]@�|�
�j�j�j
�}|j	D](��j�j��j�j
�9_��fdd��jD��_��fdd��j
D��_
q1|j	|j	7_	q"|St|�}|j	D]
�|�d�d<ql|S)Nrrhcsi|]}|�j�j|�qSr.�rlr��rCr�r.r/rp�rxz'prodHclass.__rmul__.<locals>.<dictcomp>csi|]}|�j�j|�qSr.�rmrsr�r.r/rp�rxr)r�r�r�rSr�rlrnr	rr�r%r�rlrmrTr)r�r�r�Zpbotherr�Ztemppullbackr?r.r�r/r"�s"


zprodHclass.__rmul__cCstdd�|jD��S)NcSr�r.r+r�r.r.r/r��r^z'prodHclass.evaluate.<locals>.<listcomp>)rEr�r�r.r.r/r��r�zprodHclass.evaluatec		s�t|jg�}|jD]��tt�j�t�j�d�}|��}dd��jD�}t	�j�
��D]}|�j|d�|�q*|D]}||sF|�
|�q;|D]p}t��||D]}��t�j|d����qRt����fdd�t	t���D��t�j|d�j|d�d�}|j�dd	�}��fd
d�||D�}t�j|dt���fdd�||D�||d
�}|�|||�}qI|�|j�j�j�}||7}q	|S)NricSrXr.r.�rQrr.r.r/rp�rqz.prodHclass.toprodtautclass.<locals>.<dictcomp>rrcr�rrr.ro)�	usedmarksr.r/rp�ry�rMFr�cs.g|]����fdd��jj�dd�D��qS)cs$i|]}|��j�d|�qSrr�rrs)�rndicr�r=r.r/rp�riz9prodHclass.toprodtautclass.<locals>.<listcomp>.<dictcomp>Fr�rbr�)r�r�rr/r��raz.prodHclass.toprodtautclass.<locals>.<listcomp>csg|]
}�jj|dd��qSrarbr�r_r.r/r��r#)�T)r�r�r�rSrr�rTrkrr3r7rr�r`rZrr�rGr9r1r}�forgetful_diagonalrqrerlrm)	r�r�Ztempres�	spacelistr=rZHclass�legdicsZ	diagclassr.)r�r�r�r/r&�s:

�"��
zprodHclass.toprodtautclassNc4sj|j}�dur|��dkrdd�t|���D��ntd���dur5|��dkr1dd�|��D��ntd�������fdd	�|jd
d�D��
|��|��}|t�
�krjt	d�t
|�t
|�t
��t
��fatd
��t
t|��}�
fdd	�|D�}|g}g}	g}
g�g}�fdd	�t|���D��d}|D]A}
||��}|j|
dd�\�}}�|��|�|�|	���|
�|���|�|���t|�dkr҈�|d�|d7}q�|��|	��|
�����|��t
|�}|d|_��fdd�t|���D���fdd��D��|jD]���fdd��jD��_��fdd��D��_�qt|�D�]�t|�dg�}|�}|	��|���fdd��D����fdd�tt����D��|jD�]̉�j}��fdd	�t|���D�}|j|�fdd	�|j�d
d�D�d
d�\}�}�fdd��D�}|
���}tt
�j���dg�d}|j�j|d�|��t||ddd�}|jd
d�d\}}|D�]b\}�	��}|��|��k�rFt
���|��} �fdd��D�}!�jt|!||| �t|!||| �9_�	fd d��	D��
��fd!d��jD��_�j� ��
��fd"d�|D��|!||�j||<|!||�j||<|j����qɈ	|�!||�}"||"}#�j"|#\}$��j#|$\}%}&t$|%|&�j�%d�}'|�!||�|�!||�g}(|(d|(dk�r�|(�d�|j|(�fd#d	�|j|"d
d�D�d
dd$�\})}*}+��fd%d�|j|"d
d�D�},|)j|,|'dd�|)��t&|%|&|)�}-|-D]h\}.}/}0}1t
���|)jd
d�d}
�j'|$|.|#|1|
d|1|
dfd&�}2�j|/9_�fd'd��D�}!|
�(|||'d�}3|2|3�j||<|2d|3�j||<t)�j|�d�j��_|j����qqɐqa|}�q-|S)(NrcSr�r�r.r�r.r.r/rp�rqz.prodHclass.gamma0_pullback.<locals>.<dictcomp>zdicv not uniquely determinedrcSrnr.r.rsr.r.r/rprqzdicl not uniquely determinedcsg|]
}|d�vr|�qSr�r.r�)�imdiclr.r/r�r#z.prodHclass.gamma0_pullback.<locals>.<listcomp>Fr�zWarning: edge numberszEdge numberscrbr.r.ro)�
extraedgesr.r/r�r^crbr.r.r�)r�r.r/r�r^T)�adddatarMcsi|]	}��||�qSr.r.r�)r��vimagesr.r/rp3rycr�r.r.rsr�r.r/rp4r�c�i|]
}|��j|�qSr.r�r�)�dicvisomr�r.r/rp6r#csi|]
}|�j�|�qSr.r�rs)�diclisomr�r.r/rp7r#cr�r.r.r�)�diccvr.r/rp@r�csi|]	}|��|�qSr.r.r�)�
edgenumber�vnumbersr.r/rpArycsg|]}�j|�kr|�qSr.r�r�)�avr�r.r/r�Grxcrr.r�rsr_r.r/r�Mr�)�
outgoing_legsr�cr�r.r.r�)�dicvextractr.r/rpOr�)r])r�r�cr�r.r.rs�r�r.r/rphr�cr�r.r.r�)r�r.r/rpmr�cr�r.r�r�)�diccvinv�termr.r/rpnr#cs"i|]
}|����|�qSr.r.r�)r��
dv1inverser��vextractdicr.r/rpor�crbr.r.)rQ�ler�r.r/r��s�)r�r�rmcr�r.r.rs)r��	spacediclr.r/rp�ry)�specialv�specialecr�r.r.rsr�r.r/rp�r�)*r�r7r3r�r{r�r�r�r9r�rZ	exampullbr*r2r|r~r~r�r`r
r�rlrmr	r�rrr.r}r�rTrQrr�rrrr}�Hbdrystructures�replace_space_by_GstgraphrO�dicv_reconstruct)4r��gamma1r�rUr�Zdelta_eZ	edgeorderZ
contredgesZ
contrgraphZactvertZ
edgegraphsZ
contrdictsr>r�Z	gammatildZ	edgegraphZvnumr�Z	newresultZgam0r�ZactverticesZ
gammaprimeZdiclextractZdicvextractinvZegraphZeshiftr�r�r�Zgammadegr�rZ
dl1inverseZvactiveprimeZvactiverZgspZHspZ	numHmarksZvactiveprimepreimZegrZdvex�dlexr�Z	degenlistrf�multZ	degendicvZ	degendicl�speciale_imZeindexr.)r�r�r�rUr�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r�r/r%�s�







 �0 
�����NzprodHclass.gamma0_pullbackcCs|Sr�r.r�r.r.r/r!�szprodHclass.consolidatecCs8dt|j�d}|jD]
}|t|�d7}q|�d�S)Nrwr^r�)r�r�r�ry)r�rCr�r.r.r/r��s

zprodHclass.__repr__r�)r�r�r�rMr�r�r�rrrr#r"r�r&r%r!r�r.r.r.r/r	zs	
'F
r	c
sht||�\}}|��dkrKz||}WntygYSw|jdd�d\}}g}|D]\}	}
�}|�|	|
�|||d|||dig�q-|S|��dk�r2|����fdd�td|d�D��dd��D�}|jdd�d\}}|jd	d�}
|�|�}|
|�	|�|
d|�	|�g}t
j|�D]��t|
�}|d��fd
d�tt
���D�7<|d��fdd�tt
���D�7<|�d�|�d�ks�|�d�|�d�kr�d|dvr�d�nd�|�d}z;||���tt|���f}|D]'\}	}
�}|�|	|
��fdd
��D�|||d||||d|if�q�Wq�t�y/Yq�w|SdS)NrFr�rrMcrYr.r.ro)�presentmarksr.r/r��r[z#Hbdrystructures.<locals>.<listcomp>cSsg|]}ddg�qSr�r.r�r.r.r/r��r^Tc� g|]}�|dkr�|�qSr�r.r���distri�forgetmarksr.r/r��rmcr�rrr.r�r�r.r/r��rmc�i|]}|�|�d�qS�rMr.r�)r�r�r.r/rprxz#Hbdrystructures.<locals>.<dictcomp>)�preHbdrystructuresr7rYr�r�rzr3rr�r�r_r�rr9rr[rG)r+r4r:ZpreHbdryr��
tempresultr�r�r�rfr�rUrkr!Zve0Zlgscpy�edr.)r�r�r�r�r�r/r��sT�,
((4"����r�c
s�t||d�}t|�dkritt||�j���fSt|dj���}i}|D�]�}t||�}|j��}|�r�|d}d}	|D]$\}
}z|�||d||df�|	d7}	Wq=tt	fyaYq=w|jj
dd�}dd�t|���D��|jjdd�D]}
|
|kr�|�
|
d�\}}}���fd	d��D��q{|��dkr�||vr�g||<||�|t|	�t|�d
d�t|j���D�|d|d|d|dig�||�|t|	�t|�dd�t|j���D�|d|d|d|dig�n�|�d�|�d�k�s|�d�|�d�k�rd|jddd�v�rd�nd�|�|d��d}|���}|j�dd�}|�||�|��t|�}z+|||f�|t|	�t|���fd
d��D�|d|||d|d|ig�Wn1t�y�|t|	�t|���fdd��D�|d|||d|d|igg|||f<Ynw|�d�|�d�k�r�|dk�r�|||f�|t|	�t|���fdd��D�|d|||d|d|ig�|s5q%||fS)NrrTrlcSrnr.r.r�r.r.r/rp&rqz&preHbdrystructures.<locals>.<dictcomp>Fr�cr�r.r.r�)r��	diccv_newr.r/rp*rycSr�r�r.r�r.r.r/rp5rqrMcSr�r�r.r�r.r.r/rp7rqcr�r�r.r��r�r�r.r/rpKrxcr�r�r.r�r�r.r/rpNrxcs"i|]
}|�|d�d�qSrOr.r�r�r.r/rpSr�)r�r9rr�rzrsr�r�rYr*r|r3r7r~r�rrrr�r]r[)r+r4ZHbdryr�r�rfr�ZedgsZecontrr�r�rUZcontrGrr�r��d1�d2Z	eswitchedrZmarknsr.)r�r�r�r/r�sv


��0�0�@
0
�0�� 0���=r�c@sHeZdZddd�Zdd�Zdd�Zdd	�Zd
d�Zdd
�Zddd�Z	dS)rNcCs�||_||_||_|durdd�t|���D�|_n||_|dur,dd�|��D�|_n||_|dur<t|���|_	dS||_	dS)NcSr�r�r.r�r.r.r/rperqz(decHstratum.__init__.<locals>.<dictcomp>cSrnr.r.rsr.r.r/rpjrq)
r�rrr3r7rlrzrmrNrT)r�r�rrrlrmrTr.r.r/r�`s
zdecHstratum.__init__cCs t|j|j|j|j|j|jf�Sr�)r�r�rrrlrmrTr�r.r.r/r�sr_zdecHstratum.__repr__cCr�r�r.r�r.r.r/r�vr�zdecHstratum.__neg__cCst|�}|j|9_|Sr�)rrTr�r.r.r/r"yszdecHstratum.__rmul__c
s0t|�}t�j�jd�}|��}�fdd�|D����fdd�t�j���D��t�fdd�|D��fdd��D�g�}�fdd�t�j���D���fd	d�|D�}�fd
d�|D�}t|g�}|D]2�t|�}tt	|��D]!}t
��fdd�|||D��}	|	��|	��}	|�
|g|	�}qo||7}qc|S)Nrics i|]}|�j|d���qSrr)rr�r�r�r.r/rp�rmz2decHstratum.prodforgetpullback.<locals>.<dictcomp>c	sFg|]}tttd��j|dd��t�j|d�����qSrg)r2rZr3rr�r�)r�r�r.r/r��s>�z2decHstratum.prodforgetpullback.<locals>.<listcomp>crRr��rr�r�r.r/r��rycs"g|]
}ttd�|d���qSrrr�r�)r�r.r/r��r�cs6g|]}t�j�|�gt�j|d���gg��qSrr)r1r�rr2rr�ror�r.r/r��s.�c�(g|]���fdd�tt���D��qS)cs$g|]}�|��j|d��qSrr)r}rro)rCr�r.r/r��ri�=decHstratum.prodforgetpullback.<locals>.<listcomp>.<listcomp>rkr�r�rBr/r��r�cr�)cs g|]}t�|�|d��qS)ri)rSro)rC�
trivgraphsr.r/r��rmr�rkr�)r�rBr/r��r�csg|]}�|��|��qSr.)r�ro)�
forgetlegsrCr.r/r��rx)r2rSr�rTrer3r7r1r�r9rr�r&rq)
r�r��alistZdecsZ	splitdecsZresultgraphr�r�rAr�r.)r�r�rCr�r�r/�prodforgetpullback�s.�(
�
 
zdecHstratum.prodforgetpullbackcsdd��jD�}t�j���D]}|�j|d�|�q|D]}||s+|�|�q t|�}��|�}�fdd�|D�}dd�|D�}d}|j	D]6}	d}
tt
|��D]'}|	|j��so|
t|||	|j
d�����9}
qT|
|||	|��9}
qT||
7}qJ|S)	NcSrXr.r.r�r.r.r/rp�rqz(decHstratum.evaluate.<locals>.<dictcomp>rcsg|]	}t�j|��qSr.)rrr�r�r.r/r��ryz(decHstratum.evaluate.<locals>.<listcomp>cSsg|]}t|j|��g��qSr.)r	r�r
)rQr�r.r.r/r��rxrri)rr3r�r7rr�r`r2r�r�r9r�rjrTr�r�)r�r�r=rr�ZpfprfZprodGrr�r�r�r?r.r�r/r��s(
�

$
zdecHstratum.evaluatecs���fdd�t�j���D�}|��|���t�j���j����j���fdd��jD��|D�]c}�j�	�}�j
|d������fdd�|��D�}|�
|�|��\}	�}
���fdd�|��D���fdd��D�}tt��d	g�d�|�|��i}i}
i��j���	|���d
d��jj|dd�D�}�j�	��_�j�||||
���j����|��fd
d��D��||kr�|
�|d	|d	���|
�|d|d��f}�j
�|�t��D]0}�j
|	|\}�
|�d}����
�fdd��jj|�	ddd�D�}�j
�||g�q�j�|�}t|�	d�D]
}�j|d�j|<�q,t�	d�	d��D]}|�j|<�qEtgg�}�jD]=\}}}dd�|D�}|�|��|dd�t��D�7}t||fg|g�}|t���	fdd�tt���D��9}||7}�qV|�_q3dd��jD��
�j
D]	\�}d�
�<�q��
fdd��
D�}d}|D]�t�j����}|��d	k�r�||�d	�9}�q�d	}�j|9_|du�r�|SdS)Ncs"g|]
}�j|d�kr|�qSr�r�r�)rr�r.r/r��r�z9decHstratum.replace_space_by_Gstgraph.<locals>.<listcomp>cs i|]}|�d�j|�qSrrr�rs)�gluein�
maxspacelabelr.r/rp�rmz9decHstratum.replace_space_by_Gstgraph.<locals>.<dictcomp>rcrYr.r.rs)r[r.r/r��r[csi|]	}|�vr||�qSr.r.rs)�
forgetdiclr.r/rp�rycr�r.r.rs)�dicl_vr.r/rp�r�rcSrnr.r.rsr.r.r/rp�rqFr�cr�r.r.rs)r&r.r/rp�r�c
s.i|]}|�����|�|���qSr.rrs)r��dil_inverser��	pre_diclbr]r.r/rp�s&�cSror�r.rsr.r.r/r�r[cSr<r.r.ror.r.r/r�
r=cs2g|]�t���fdd�t��D�����qS)cs,g|]}t�d|�d��d��qSrrrr�)rA�num_newvert�numvert_oldr.r/r�r\zDdecHstratum.replace_space_by_Gstgraph.<locals>.<listcomp>.<listcomp>)rEr3r�)r�r�r�r�r/r�s���cSr�rLr.r�r.r.r/rprqTcsg|]}�|s|�qSr.r.r�)�
spacesusedr.r/r�r[)r3r�r7r
r
r.rr`rr|rr�rzr�r�r�r2r}rr1r~rr�rlrrTrr9rr�rS)r�rrfr�r�Z	averticesr=Z	gluegraphZ
unusedlegsZ
forgetdicvZ
forgetdichZdicl_v_inverser$r%Z
dic_voutgoingr�rZpre_br6ZdiclbZvnumbr�r�r�r�r�r�r�Zunusedspacesr�Z	trivGraphr.)rr�r&r�r�r�r�r�r�r�r�r�r]r�r[r/r��s�






��



�
�z%decHstratum.replace_space_by_Gstgraphr�r�)
r�r�r�r�r�r�r"r�r�r�r.r.r.r/r_s

rc
st��}|durttt�gttd�d��gg��g�}t�fdd�t|�D��fdd�t|�D�g�}t|��fdd�t|�D�g�}��fdd�t|�D�}��fdd�t|�D�}	|dk�rEtdd	d
�d
�d�D]}
t��|
�s�td|
��f�qpt��gttd�d��ttd�d��gg�}t|g�}tdd
�d
�d�D]�}
t	��|
�}t	��d
�d
�|
�}t
��|
ttd�d�����fdd�|D�}t
��d
�d
�|
ttd�d�����fd
d�|D�}t
��t|�t|�|
�}tt|��D](}tt|��D]}|||fdk�r/|j�|||f||||g��q�q
q�td|�D]}|�d|g|�}�q9|�dg|���}|jD]}t|�D]}||�||�||<||�|	|��qW�qQt�fdd�t|�D�dd��D�g�|_|��S)Nrcrnr.r.ror�r.r/r�7r=z&forgetful_diagonal.<locals>.<listcomp>csg|]}ttd�d���qSrrr�ror�r.r/r�7rxc
s.g|]}tt�gttd�d��gg���qSrr)rSr1r2r3ror4r.r/r�8racs*g|]���fdd�td�d�D��qS)cs g|]}|����vr|�qSr.r�r�)r?r�r.r/r�<rmz1forgetful_diagonal.<locals>.<listcomp>.<listcomp>r)r3r�)r�r,rfr/r�<r�cs.g|]����fdd�tt����D��qS)cs&i|]}����||d�qSrrr.r�)r?r��leglistsr.r/rp=r�z1forgetful_diagonal.<locals>.<listcomp>.<dictcomp>rkr�)r�r�rfr/r�=rarrMr%zKIn computation of diagonal : H^%s(bar M_%s,%s) not necessarily tautologicalcr7r.r8r�)�strata1r.r/r�Lr[cr7r.r8r�)�strata2r.r/r�Nr[crnr.r.ror�r.r/r�br=cSror�r.rsr.r.r/r�br[)r9r�rSr1r2r3r�r.r�rr#rr[�
inverseintmatr�r�rqr&r�r}r�r!)r+r,r�r�r�r;r�r�r�rc�rdegZDgamma�Deltar��gi1�gi2Zgens1�gens2Z	invintmatrr6r?r�r.)r+r�r�r,r�r�r/r�0sN(0 
"�0
,$���
�*r�cCs�|td|d|�dkr!tt�||||ttd|d����}ntt�|||d|d||ttd|d������}|����S)Nr%rMr)rrr#rr[r3r<r2�r+r,r�r�r��intmatr.r.r/r�gs&8r�csNt|||��t||d|d||��t���fdd�|D��}|����S)Nr%cs"g|]
����fdd��D��qS)cs g|]}�|�����qSr.r+ro)rA�tg1�tg2r.r/r�srmz-inverseintmat2.<locals>.<listcomp>.<listcomp>r.r��r�r�r�r�r/r�sr�z"inverseintmat2.<locals>.<listcomp>)�tautgensrr<r2r�r.r�r/�inverseintmat2psr�c
sT���dkrdd�t����D�S���fdd��D�}tt�����t|�}t�fdd��jdd�D��}t|�}|r�t�}|��D]_}��|d	�|vru��|d�}	|�|�|	|vrt|��|d	�||	<|�|	�|�|	�qD��|d�|vr���|d	�}	|�|�|	|vr�|��|d�||	<|�|	�|�|	�qD|}|s=|S)
NrcSr�r�r.r�r.r.r/rp�rqz$dicv_reconstruct.<locals>.<dictcomp>cr�r.r�rPr�r.r/rp�r�c3r�r�r�r�r�r.r/rV�r�z#dicv_reconstruct.<locals>.<genexpr>Fr�r)	r7r3rZr�r|r�r�r�r^)
r�r�rUr�r�r�r�r�r�r�r.r�r/r��s8





��r�cCs(|dkrdS|dkr|ddkrdS|dkr|dkrdS|dkr*|dkr*|dkr*dS|dkr:|ddkr:|dkr:dS|dkrD|d	krDdS|dkrN|d
krNdS|d	krX|dkrXdS|d	krb|dkrbdS|d	krl|dkrldS|d
krv|dkrvdS|dvr|dS|dvr�dSdd	|d	||d
vr�dSdS)NrTrrMr/�F�r%r�)rrM)rr%�)rrrMr%r�r.)r+r,r;r.r.r/r.�s:r.zKhttps://modulispaces.gitlab.io/relations-database/FZ_conjecture_holds_filesr"cs��dks�dks�dks�d�d�krdSt����}t|�}|dkr�t������fdd�|D�}t��d�d����dd�tt�����D�}ttdd�t|�D�g�}	t|�D])\}
�|	tt��fd	d�|D�g�7}	|s�t	|
d
|	�
�f�|	�
�|kr�dSqadSt����\}}|��|�
�|kr�|s�t	dt
���f��dSt���fd
d�td
��D���r?t��d
���r?t|gt���dd�ggdd�}|��|�
�|kr�|s�t	dt
���f��dSt�d
�d���r?t�d
gttd
�d��g�d
�dfg�}
t|gt���|
d�ggdd�}|��|�
�|k�r?|�s=t	dt
���f��dS|�sat	dt
���f�d�t	dt
|��t	dt
|�
���dS)a�
    Checks if the set of generalized Faber-Zagier relations [PPZ15]_ in R^d(Mbar_{g,n}) is complete.

    It does so by comparing the rank of the quotient of the strata algebra by the FZ-relations
    to a lower bound for the rank of the cohomology group R^d(Mbar_{g,n}).

    For method = 'pair', this lower bound is obtained as the rank of a matrix of intersection
    numbers of generators of R^d(Mbar_{g,n}) with generators in opposite degree.

    For method = 'pull', the lower bound arises from the rank of a matrix obtained from
    intersection numbers with kappa-psi-monomials and boundary pullbacks to products of spaces
    Mbar_{gi, ni} for which the FZ-conjecture is checked recursively.

    For quiet = False, the program gives status reports about the progress of the computation.

    EXAMPLES::

        sage: from admcycles.admcycles import FZ_conjecture_holds
        sage: FZ_conjecture_holds(1,4,1)
        True
        sage: FZ_conjecture_holds(2,3,1,method='pull')
        True
    rr%Tr"crbr.r.ro)�pgensr.r/r�6r^z'FZ_conjecture_holds.<locals>.<listcomp>cSsg|]}|d�qSrrr.ror.r.r/r�8r^cSr�r�r.ror.r.r/r�:r=csg|]
}|�����qSr.r+r�)�cogensr�r.r/r�=r#rFz"FZ-conjecture holds for (g,n,d) = c3sf�|].}td�d�D]$}t�d�D]}�|d�|d�|dkp,t|||�VqqqdS)rrMr%N)r3�FZ_conjecture_holds)rQ�gi�nir)r�r+r,r.r/rVOs�dz&FZ_conjecture_holds.<locals>.<genexpr>)r=rrM)r:z/FZ-conjecture cannot be verified for (g,n,d) = �!z$Rank of quotient by FZ-relations  : z$Rank of intersection and pullback : )rr9r�r�random_elementrrr3rHr�rrGrr��allr�rr;r!r2)r+r,r�r2�quietr�Zquotdimr�Zper�spacer?r�r�Zibdr.)r�r�r+r,r�r�r/r�s\, �"� 0 r��bettic
CsTd}|dkrtj}dd�|��D�}|dkr"tj}dd�|��D�}tttdd�|D����}td	d�|D��}d
}t|d�D]}|dt	|�d
7}q@|d7}t
|�D]R\}\}}	|dkri|||ddkss|	||ddkrw|d7}|t	|�d
t	|	�d
7}t|d�D]}||	|f|vr�|t	|||	|f�d
7}q�|d
7}q�qU|S)a
    Returns string representing ranks of the tautological ring (for output='betti') or
    cases where the Faber-Zagier conjecture has been verified (for output='FZconfirm').

    EXAMPLES::

        sage: from admcycles.admcycles import FZresulttable
        sage: # FZresulttable throws an error if there aren't any results stored
        sage: # To make the success of the doctest independend from the order in which
        sage: # the doctests are executed we just store something.
        sage: from admcycles import generating_indices
        sage: g = generating_indices(0,3,0)
        sage: s = FZresulttable(output='betti')
    zg	n	r=0rcSs,i|]\}}|d|d|dft|��qS�rrrM)r9r r.r.r/rp{�,z!FZresulttable.<locals>.<dictcomp>Z	FZconfirmcSs(i|]\}}|d|d|df|�qSrr.r r.r.r/rp~r�css�|]
\}}}||fVqdSr�r.)rQr+r,r�r.r.r/rVr;z FZresulttable.<locals>.<genexpr>css�|]\}}}|VqdSr�r.)rQr�r;r.r.r/rV�r�zg	n	rzr=�	r^r)rr_rIr�rGr2rZr.r3r�rH)
�outputr�ZgicacheZ	bettidictZgnknownsrar;r?r+r,r.r.r/�
FZresulttableis.0
�rcCsddlm}|||��|�S)a>
    Returns a list of the polynomials in kappa and psi classes on Mbar_{g,n} of degree d.

    EXAMPLES::

      sage: from admcycles.admcycles import kappapsipolys
      sage: for a in kappapsipolys(0,4,1):
      ....:     print(a)
      Graph :      [0] [[1, 2, 3, 4]] []
      Polynomial : (kappa_1)_0
      Graph :      [0] [[1, 2, 3, 4]] []
      Polynomial : psi_1
      Graph :      [0] [[1, 2, 3, 4]] []
      Polynomial : psi_2
      Graph :      [0] [[1, 2, 3, 4]] []
      Polynomial : psi_3
      Graph :      [0] [[1, 2, 3, 4]] []
      Polynomial : psi_4
    rrs)r�r��kappa_psi_polynomials)r+r,r�r�r.r.r/rE�srEcC�ddlm}|dd�dS)z�
    Saving previously computed Faber-Zagier relations [PPZ15]_ to file new_geninddb.pkl.

    Deprecated. Saving and loading of FZ relations is now handled automatically.
    rr&�z@Saving and loading of FZ relations is now handled automatically.N�r)r'r&r.r.r/�save_FZrels��rcCr)z�
    Loading values -- Deprecated
    Please run convert_old_FZ_database() ones to convert your cache to the new format.
    Saving and loading of FZ relations is handled automatically afterwards.
    rr&r	z�The format of the cache file has changed. Please run convert_old_FZ_database() ones to convert your cache to the new format. Saving and loading of FZ relations is handled automatically afterwards.Nr
r&r.r.r/�load_FZrels�rr
cCs�d}t|d��
}t�|�}Wd�n1swY|d��D]}tj|d|g|d�R�q"|d��D]}tj|d|g|d�R�q:|d��D]}tj|d|g|d�R�qRdS)a%
    Converts the relations saved using the old method.
    Converts the `new_geminddb.pkl` file to a different file for each combination of a function and its arguments.
    The old file contains data for the functions ``generating_indices``, ``genstobasis`` and ``FZ_conjecture_holds``.
    znew_geninddb.pkl�rbNrrrM)�open�pickle�load�keysrrrr�)Zold_fileZold_relsZold_dicr��gbZfzchr.r.r/�convert_old_FZ_database�s�   �rcC�"tttg}|D]}|�|�qdS)a�
    Temporarily set online lookup for all supported functions.
    Use func:`set_online_lookup_default` to save a default setting.

    Those are currently :func:`genstobasi`, func:`generating_indices`, func:`FZ_conjecture_holds`.

    EXAMPLES::

        sage: from admcycles.admcycles import set_online_lookup
        sage: from admcycles.admcycles import genstobasis, generating_indices, FZ_conjecture_holds
        sage: functions = [genstobasis, generating_indices, FZ_conjecture_holds]
        sage: set_online_lookup(True)
        sage: assert all(f.go_online == True for f in functions)
        sage: set_online_lookup(False)
        sage: assert all(f.go_online == False for f in functions)
    N)rrr��set_online_lookup�r6�	functionsr�r.r.r/r�s
�rcCr)z�
    Sets a default for online lookup for all supported functions.
    Use func:`set_online_lookup` for a temporary setting.

    Those are currently :func:`genstobasi`, func:`generating_indices`, func:`FZ_conjecture_holds`.
    N)rrr��set_online_lookup_defaultrr.r.r/r�s
�rcCs tttg}|D]}|��qdS)zC
    Download the remove database for all supported functions.
    N)rrr�Zdownload_all)rr�r.r.r/�download_FZ_databases

�rcCs|j}tt|�dd�d�}dd�|D�}dd�|D�}t|j|�}g}d}	|j��}
tt|��D]}t|
�||d}|�	t
t|	d|	|d���q0g}
|D]	}|
�	||�qQt||f}|D] }t|��
t|��r�t|�t|�}t||�}|�t
|��}qcdS)	NcSs|dS)Nrr.)rzr.r.r/rxszHdb_lookup.<locals>.<lambda>rIcS�g|]}|d�qSr�r.ror.r.r/r�r^zHdb_lookup.<locals>.<listcomp>cSrrrr.ror.r.r/r�r^rr)rtrGrHrr<rr3r9rr�r2r/rZr�rr�)r+rrMrOZsort_liZ	ind_reordZli_reordZ	dat_reordZmn_listZ	num_marksr�r>Z	new_marksZmn_reordr?r5rNr6r�r.r.r/�
Hdb_lookups,
"��rcCsddlm}|||���S)z4
    Return the fundamental class of \Mbar_g,n.
    rrs)r�r��fundamental_class)r+r,r�r.r.r/�	fundclass3srcCs^|rtj||ttd|d��t|dd�d�}dd�|D�Sddlm}|||t|�d��|�S)	a?
    Returns a lists of all tautological classes of degree r on \bar M_{g,n}.

    INPUT:

    g : integer
      Genus g of curves in \bar M_{g,n}.
    n : integer
      Number of markings n of curves in \bar M_{g,n}.
    r : integer
      The degree r of of the classes.
    decst : boolean
      If set to True returns generators as decorated strata, else as tautological classes.
    moduli : string
      The moduli type (one of 'st', 'tl', 'ct', 'rt', 'sm').

    EXAMPLES::

      sage: from admcycles import *

      sage: tautgens(2,0,2)[1]
      Graph :      [2] [[]] []
      Polynomial : (kappa_1^2)_0

    ::

      sage: L=tautgens(2,0,2);2*L[3]+L[4]
      Graph :      [1] [[2, 3]] [(2, 3)]
      Polynomial : (kappa_1)_0
      <BLANKLINE>
      Graph :      [1, 1] [[2], [3]] [(2, 3)]
      Polynomial : 2*psi_2
    rTr�r�cS�g|]}t|��qSr.r8rsr.r.r/r�br^ztautgens.<locals>.<listcomp>rsr�)r#rr[r3rr�r�rD)r+r,r;�decstr~r)r�r.r.r/r�>s
"(r�cCsBt|||�}tt|��D]}tdt|�dt||��qdS)a�
    Lists all tautological classes of degree r on \bar M_{g,n}.

    INPUT:

    g : integer
      Genus g of curves in \bar M_{g,n}.
    n : integer
      Number of markings n of curves in \bar M_{g,n}.
    r : integer
      The degree r of of the classes.

    EXAMPLES::

      sage: from admcycles import *

      sage: list_tautgens(2,0,2)
      [0] : Graph :      [2] [[]] []
      Polynomial : (kappa_2)_0
      [1] : Graph :      [2] [[]] []
      Polynomial : (kappa_1^2)_0
      [2] : Graph :      [1, 1] [[2], [3]] [(2, 3)]
      Polynomial : (kappa_1)_0
      [3] : Graph :      [1, 1] [[2], [3]] [(2, 3)]
      Polynomial : psi_2
      [4] : Graph :      [1] [[2, 3]] [(2, 3)]
      Polynomial : (kappa_1)_0
      [5] : Graph :      [1] [[2, 3]] [(2, 3)]
      Polynomial : psi_2
      [6] : Graph :      [0, 1] [[3, 4, 5], [6]] [(3, 4), (5, 6)]
      Polynomial : 1
      [7] : Graph :      [0] [[3, 4, 5, 6]] [(3, 4), (5, 6)]
      Polynomial : 1
    �[z] : N)r�r3r9r�r�)r+r,r;r)r?r.r.r/�
list_tautgensjs#"�r"cC�f|dus|durddlm}|dd�|durt�d}|dur%t�d}ddlm}|||��|�S)	a�
    Returns the (Arbarello-Cornalba) kappa-class kappa_a on \bar M_{g,n} defined by

      kappa_a= pi_*(psi_{n+1}^{a+1})

    where pi is the morphism \bar M_{g,n+1} --> \bar M_{g,n}.

    INPUT:

    a : integer
      The degree a of the kappa class.
    g : integer
      Genus g of curves in \bar M_{g,n}.
    n : integer
      Number of markings n of curves in \bar M_{g,n}.

    EXAMPLES::

      sage: from admcycles import kappaclass
      sage: a = kappaclass(1, 2, 1)
      sage: a
      Graph :      [2] [[1]] []
      Polynomial : (kappa_1)_0
      sage: parent(a)
      TautologicalRing(g=2, n=1, moduli='st') over Rational Field

    When working with fixed g and n for the moduli space `\bar M_{g,n}`, it is
    possible to construct a
    :class:`~admcycles.tautological_ring.TautologicalRing` with the desired value
    of g and n and call its method
    :class:`~admcycles.tautological_ring.TautologicalRing.kappa`::

      sage: from admcycles import TautologicalRing
      sage: R = TautologicalRing(2, 1)
      sage: R.kappa(1)
      Graph :      [2] [[1]] []
      Polynomial : (kappa_1)_0

    TESTS::

      sage: from admcycles import kappaclass, reset_g_n
      sage: reset_g_n(1, 2)
      doctest:...: DeprecationWarning: reset_g_n is deprecated. Please use TautologicalRing instead.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: a = kappaclass(2)
      doctest:...: DeprecationWarning: Use of kappaclass without specifying g,n is deprecated.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: a
      Graph :      [1] [[1, 2]] []
      Polynomial : (kappa_2)_0
      sage: parent(a)
      TautologicalRing(g=1, n=2, moduli='st') over Rational Field
    Nrr&r(z7Use of kappaclass without specifying g,n is deprecated.r+r,rs)r)r'�globalsr�r�r�)rr+r,r'r�r.r.r/�
kappaclass�s6


r%cCr#)	aO
    Returns the class psi_i on \bar M_{g,n}.

    INPUT:

    i : integer
      The leg i associated to the psi class.
    g : integer
      Genus g of curves in \bar M_{g,n}.
    n : integer
      Number of markings n of curves in \bar M_{g,n}.

    EXAMPLES::

      sage: from admcycles import psiclass
      sage: a = psiclass(1, 2, 1)
      sage: a
      Graph :      [2] [[1]] []
      Polynomial : psi_1
      sage: parent(a)
      TautologicalRing(g=2, n=1, moduli='st') over Rational Field

    When working with fixed g and n for the moduli space `\bar M_{g,n}`, it is
    possible to construct a
    :class:`~admcycles.tautological_ring.TautologicalRing` with the desired value
    of g and n and call its method
    :class:`~admcycles.tautological_ring.TautologicalRing.psi`::

      sage: from admcycles import TautologicalRing
      sage: R = TautologicalRing(2, 1)
      sage: R.psi(1)
      Graph :      [2] [[1]] []
      Polynomial : psi_1

    TESTS::

      sage: from admcycles import psiclass, reset_g_n
      sage: reset_g_n(2, 2)
      doctest:...: DeprecationWarning: reset_g_n is deprecated. Please use TautologicalRing instead.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: a = psiclass(1)
      doctest:...: DeprecationWarning: Use of psiclass without specifying g,n is deprecated.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: a
      Graph :      [2] [[1, 2]] []
      Polynomial : psi_1
      sage: parent(a)
      TautologicalRing(g=2, n=2, moduli='st') over Rational Field
    Nrr&r(z5Use of psiclass without specifying g,n is deprecated.r+r,rs)r)r'r$r�r�r�)r?r+r,r'r�r.r.r/�psiclass�s2


r&cCsh|dus|durddlm}|dd�|durt�d}|dur%t�d}ddlm}|||��||�S)	a?
    Returns the pushforward of the fundamental class under the boundary gluing map \bar M_{g1,A} X \bar M_{g-g1,{1,...,n} \ A}  -->  \bar M_{g,n}.

    INPUT:

    g1 : integer
      The genus g1 of the first vertex.
    A: list
      The list A of markings on the first vertex.
    g : integer
      The total genus g of the graph.
    n : integer
      The total number of markings n of the graph.

    EXAMPLES::

      sage: from admcycles import sepbdiv

      sage: a = sepbdiv(1, [1,3], 3, 4)
      sage: a
      Graph :      [1, 2] [[1, 3, 5], [2, 4, 6]] [(5, 6)]
      Polynomial : 1
      sage: a
      Graph :      [1, 2] [[1, 3, 5], [2, 4, 6]] [(5, 6)]
      Polynomial : 1
      sage: parent(a)
      TautologicalRing(g=3, n=4, moduli='st') over Rational Field

    When working with fixed g and n for the moduli space `\bar M_{g,n}`, it is
    possible to construct a
    :class:`~admcycles.tautological_ring.TautologicalRing` with the desired value
    of g and n and call its method
    :class:`~admcycles.tautological_ring.TautologicalRing.sepbdiv`::

      sage: from admcycles import TautologicalRing
      sage: R = TautologicalRing(3, 4)
      sage: R.sepbdiv(1, [1,3])
      Graph :      [1, 2] [[1, 3, 5], [2, 4, 6]] [(5, 6)]
      Polynomial : 1

    TESTS::

      sage: from admcycles import sepbdiv, reset_g_n
      sage: reset_g_n(2, 2)
      doctest:...: DeprecationWarning: reset_g_n is deprecated. Please use TautologicalRing instead.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: a = sepbdiv(1, [1])
      doctest:...: DeprecationWarning: Use of sepbdiv without specifying g,n is deprecated.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: parent(a)
      TautologicalRing(g=2, n=2, moduli='st') over Rational Field
    Nrr&r(z4Use of sepbdiv without specifying g,n is deprecated.r+r,rs)r)r'r$r�r��separable_boundary_divisor)r7r�r+r,r'r�r.r.r/�sepbdivs5


r(cCsdddlm}|dus|dur|dd�|durt�d}|dur%t�d}ddlm}|||���S)	a�
    Returns the pushforward of the fundamental class under the irreducible boundary gluing map \bar M_{g-1,n+2} -> \bar M_{g,n}.

    INPUT:

    g : integer
      The total genus g of the graph.
    n : integer
      The total number of markings n of the graph.

    EXAMPLES::

      sage: from admcycles import irrbdiv, reset_g_n

      sage: a = irrbdiv(2, 2)
      sage: a
      Graph :      [1] [[1, 2, 3, 4]] [(3, 4)]
      Polynomial : 1
      sage: parent(a)
      TautologicalRing(g=2, n=2, moduli='st') over Rational Field

      sage: a = irrbdiv(1, 1)
      sage: a
      Graph :      [0] [[1, 2, 3]] [(2, 3)]
      Polynomial : 1
      sage: parent(a)
      TautologicalRing(g=1, n=1, moduli='st') over Rational Field

    When working with fixed g and n for the moduli space `\bar M_{g,n}`, it is
    possible to construct a
    :class:`~admcycles.tautological_ring.TautologicalRing` with the desired value
    of g and n and call its method
    :class:`~admcycles.tautological_ring.TautologicalRing.irrbdiv`::

      sage: from admcycles import TautologicalRing
      sage: R = TautologicalRing(1, 1)
      sage: R.irreducible_boundary_divisor()
      Graph :      [0] [[1, 2, 3]] [(2, 3)]
      Polynomial : 1

    TESTS::

      sage: from admcycles import irrbdiv, reset_g_n
      sage: reset_g_n(1, 1)
      doctest:...: DeprecationWarning: reset_g_n is deprecated. Please use TautologicalRing instead.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: irrbdiv()
      doctest:...: DeprecationWarning: Use of irrbdiv without specifying g,n is deprecated.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      Graph :      [0] [[1, 2, 3]] [(2, 3)]
      Polynomial : 1
    rr&Nr(z4Use of irrbdiv without specifying g,n is deprecated.r+r,rs)r)r'r$r�r��irreducible_boundary_divisor)r+r,r'r�r.r.r/�irrbdivPs5


r*cGs�t|�dkrt|dt�r|d}tdd�|D��std��t|�}t|�}||dr0td��||dd}ddlm}|||�}d	d
�t|�D�}||�	�|d��
�S)a_
    Return the integral of psi classes.

    Given either a sequence k1, ..., kn of non-negative integer arguments or
    a single list containing such numbers, this function computes the integral

    \int_{Mbar_g,n} psi_1^k1 ... psi_n^kn .

    EXAMPLES:

    Examples in genus 0::

      sage: from admcycles import psi_correlator
      sage: psi_correlator(0,0,0)
      1
      sage: psi_correlator(1,0,0,0)
      1
      sage: psi_correlator(0,2,0,0,0)
      1
      sage: psi_correlator(1,1,0,0,0)
      2

    Examples in genus 1, with argument a list of integers::

      sage: psi_correlator([1])
      1/24
      sage: psi_correlator([2, 0])
      1/24
      sage: psi_correlator([1, 1])
      1/24
      sage: psi_correlator([3, 0, 0])
      1/24
      sage: psi_correlator([2, 1, 0])
      1/12
      sage: psi_correlator([1, 1, 1])
      1/12

    genus 2::

      sage: psi_correlator(7)
      1/82944
      sage: psi_correlator(7, 1)
      5/82944
      sage: psi_correlator(6, 2)
      77/414720
      sage: psi_correlator(5, 3)
      503/1451520
      sage: psi_correlator(4, 4)
      607/1451520
    rrcss �|]}|tvo|dkVqdSr�)rryr.r.r/rV�r�z!psi_correlator.<locals>.<genexpr>z9arguments of psi_correlators must be nonnegative integersr%z,the composition should sum up to 3*g - 3 + nrscSsi|]\}}|r|d|�qSrrr.)rQr?�kir.r.r/rp�rxz"psi_correlator.<locals>.<dictcomp>r|)r9r�rr�r*rEr�r�rH�
trivial_graphr�)�argsr,rCr+r�rrrTr.r.r/�psi_correlator�s3
r.cCs6ddlm}|dd�ddlm}|||��|�dS)Nrr&r(zehodge_chern_char is deprecated. Please use the hodge_chern_char method from TautologicalRing instead.rs)r)r'r�r��hodge_chern_character)r+r,r�r'r�r.r.r/�hodge_chern_char�s
r0cs�tt||d�d�}t�fdd�td|d�D��}t|�}||}td|d�D]}||9}|�|�|td�t|�|7}q)|S)Nrcs g|]}t|d��|��qSrr�rr���chclassr.r/r��rmz&chern_char_to_poly.<locals>.<listcomp>rrM)rr�rEr3r�rr)r3r�r+r,r�Zargum�expor5r.r2r/�chern_char_to_poly�s 
r5cs�ddlm}m}t�|�r�fdd�td|d�D��n�fdd�td|d�D��t�fdd�t|�D��}|dkrk|d	usC|d	urPdd
lm}|dd�|S|d	urYt	�d
}|d	urbt	�d}||||��
�S|j|d�S)a=
    Turns a Chern character into a Chern class in the tautological ring of \Mbar_{g,n}.

    INPUT:

    t : integer
      degree of the output Chern class
    char : tautclass or function
      Chern character, either represented as a (mixed-degree) tautological class or as
      a function m -> ch_m

    EXAMPLES:

    Note that the output of generalized_hodge_chern takes the form of a chern character::

      sage: from admcycles import *
      sage: from admcycles.GRRcomp import *
      sage: g=2;n=2;l=0;d=[1,-1];a=[[1,[1],-1]]
      sage: chern_char_to_class(1,generalized_hodge_chern(l,d,a,1,g,n))
      Graph :      [2] [[1, 2]] []
      Polynomial : 1/12*(kappa_1)_0 - 13/12*psi_1 - 1/12*psi_2
      <BLANKLINE>
      Graph :      [1] [[4, 5, 1, 2]] [(4, 5)]
      Polynomial : 1/24
      <BLANKLINE>
      Graph :      [0, 2] [[1, 2, 4], [5]] [(4, 5)]
      Polynomial : 1/12
      <BLANKLINE>
      Graph :      [1, 1] [[2, 4], [1, 5]] [(4, 5)]
      Polynomial : 13/12
      <BLANKLINE>
      Graph :      [1, 1] [[4], [1, 2, 5]] [(4, 5)]
      Polynomial : 1/12
    rr�cs0g|]}d|dt|d��j|d��qS)rCr�r;)r�
simplifiedrO��charr.r/r�s0z'chern_char_to_class.<locals>.<listcomp>cs,g|]}d|dt|d��|��qS)rCrr1rOr8r.r/r�rc3s>�|]}t|���tt|��t�fdd�|D��VqdS)c3s�|]	}�|dVqdSrNr.r��r�r.r/rVr�z0chern_char_to_class.<locals>.<genexpr>.<genexpr>N)r
�to_exprr9rrOr:r.r/rVs�<z&chern_char_to_class.<locals>.<genexpr>rNr&r(zIUse of chern_char_to_class for t==0 without specifying g,n is deprecated.r+r,r6)r�r�r�r�r3rErr)r'r$rr7)r�r9r+r,r�r��expr'r.)r�r9r/�chern_char_to_class�s #



r=cCsjddlm}|dus|dur|dd�|durt�d}|dur%t�d}ddlm}|||�j||d	�S)
ah
    Returns the tautological class lambda_d on \bar M_{g,n} defined as the d-th Chern class

      lambda_d = c_d(E)

    of the Hodge bundle E. The result is represented as a sum of stable graphs with kappa and psi classes.

    INPUT:

    d : integer
      The degree d.
    g : integer
      Genus g of curves in \bar M_{g,n}.
    n : integer
      Number of markings n of curves in \bar M_{g,n}.
    pull : boolean, default = True
      Whether lambda_d on \bar M_{g,n} is computed as pullback from \bar M_{g}

    EXAMPLES::

      sage: from admcycles import *

      sage: lambdaclass(1,2,0)
      Graph :      [2] [[]] []
      Polynomial : 1/12*(kappa_1)_0
      <BLANKLINE>
      Graph :      [1] [[2, 3]] [(2, 3)]
      Polynomial : 1/24
      <BLANKLINE>
      Graph :      [1, 1] [[2], [3]] [(2, 3)]
      Polynomial : 1/24

    When working with fixed g and n for the moduli space `\bar M_{g,n}`,
    it is possible to construct a :class:`~admcycles.tautological_ring.TautologicalRing`
    with the desired value of g and n::

      sage: R = TautologicalRing(1, 1)
      sage: R.lambdaclass(1)
      Graph :      [1] [[1]] []
      Polynomial : 1/12*(kappa_1)_0 - 1/12*psi_1
      <BLANKLINE>
      Graph :      [0] [[3, 4, 1]] [(3, 4)]
      Polynomial : 1/24

    TESTS::

      sage: from admcycles import lambdaclass, reset_g_n
      sage: inputs = [(0,0,4), (1,1,3), (1,2,1), (2,2,1), (3,2,1), (-1,2,1), (2,3,2)]
      sage: for d,g,n in inputs:
      ....:     assert (lambdaclass(d, g, n)-lambdaclass(d, g, n, pull=False)).is_zero()

      sage: reset_g_n(1,1)
      doctest:...: DeprecationWarning: reset_g_n is deprecated. Please use TautologicalRing instead.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      sage: lambdaclass(1)
      doctest:...: DeprecationWarning: Use of lambdaclass without specifying g,n is deprecated.
      See https://gitlab.com/modulispaces/admcycles/-/merge_requests/109 for details.
      Graph :      [1] [[1]] []
      Polynomial : 1/12*(kappa_1)_0 - 1/12*psi_1
      <BLANKLINE>
      Graph :      [0] [[3, 4, 1]] [(3, 4)]
      Polynomial : 1/24
    rr&Nr(z8Use of lambdaclass without specifying g,n is deprecated.r+r,rs)r)r)r'r$r�r��lambdaclass)r�r+r,rr'r�r.r.r/r>/s@


r>c
s�t||�}t|j���}|durttd|d��}t|�}t|���fdd�t|�D�}tt|gttd|d��gg�t	t|gttd|d��gg�d||fid|gg�g�S)z�Returns \bar H on genus g with Hurwitz datum dat as a prodHclass on the trivial graph, remembering only the marked points given in markingsNrcrrrr.rorr.r/rp�ryzbarH.<locals>.<dictcomp>r)
rr9r�rzr2r3rGr	r1r)r+rrMrr,r�r!r.rr/�barHzs
Vr?cs��d�dkrtdt��dtd�d�d�dSd�d�d|dkrBtdt��dt�d|�d�dStd	g��t��fd
d�td�d�D��fdd�t|�D��}ttd
�d
��ttd�dd
d�dd
d|��}td
�td�d��}|t�||d�}dd�td
�d
�D�}|�	��fdd�td�dd
d�dd
d|�D��|j
|dd�S)a�Returns the cycle class of the hyperelliptic locus of genus g curves with n marked fixed points and m pairs of conjugate points in \barM_{g,n+2m}.

    TESTS::

      sage: from admcycles import Hyperell
      sage: H=Hyperell(3) # long time
      sage: H.basis_vector() # long time
      (3/4, -9/4, -1/8)
      sage: H2 = Hyperell(1,1,1)
      sage: H2.forgetful_pushforward([3]).fund_evaluate()
      1

    rMzA hyperelliptic curve of genus � can only have � fixed points!r�The moduli space \barM_{�,�} does not exist!rOc�g|]}�d�qSrrr.ror�r.r/r��r^zHyperell.<locals>.<listcomp>crEr�r.ror�r.r/r��r^rr�cSrnr.r.ror.r.r/rp�rqzHyperell.<locals>.<dictcomp>cs"i|]
}||d�d��qSr�r.r�r4r.r/rp�r�Fr��r�r�r
r�r3r2rrr1rr}�r+r,r5r4rN�factorr�Zrndictr.�r<r+r,r/�Hyperell�s((
:@@rJcs��dkr
td�dS�d�dkr(tdt��dtd�d�d�dSd�d�d|dkrLtdt��dt�d|�d	�dStd
g��t��fdd�td�d�D��fd
d�t|�D��}ttd�d��ttd�ddd�ddd|��}tdtd�d��f�}�dkr��dkr�|dkr�|d}|t�||d�}dd�td�d�D�}|�	��fdd�td�ddd�ddd|�D��|j
|dd�S)a�
    Returns the cycle class of the bielliptic locus of genus ``g`` curves with ``n`` marked fixed points and ``m`` pairs of conjugate points in `\bar M_{g,n+2m}`.

    TESTS::

        sage: from admcycles import Biell
        sage: B=Biell(2)
        sage: B.basis_vector()
        (15/2, -9/4)
        sage: B1 = Biell(2,0,1)
        sage: B.forgetful_pullback([1]).basis_vector()
        (15/2, -15/2, -9/2)
        sage: B1.forgetful_pushforward([2]).basis_vector()
        (15, -15, -9)

    rz*There are no bielliptic curves of genus 0!rMzA bielliptic curve of genus r@rArBrCrDrOcrErrr.ror�r.r/r��r^zBiell.<locals>.<listcomp>crEr�r.ror�r.r/r��r^rr�cSrnr.r.ror.r.r/rp�rqzBiell.<locals>.<dictcomp>cs"i|]
}||d�d��qSr�r.r�r4r.r/rp�r�Fr�rFrGr.rIr/�Biell�s&((
:@@rKcCsjttt||�td�d�g�}||}|js1t||���}|��}|��}ddlm	}|||��
�S|��S)zsPulls the class alpha to the space \bar H_{g,dat} via map i forgetting the action, then pushes forward under delta.rrirs)r�rjrrNr�r�r+r,r�r�r�r�)r+rrdZHb�gam�gd�ndr�r.r.r/�	Hpullpush�srOc
Cslt||||d�}t||||d�}t|�}g}t|�D]}t||||�}	|	|d8<|�|	�qt|�S)Nr�r)rrr9r3�	insertvecr�r)
r+r,r;r~�genindZgentobZnumgensr�r?r=r.r.r/�
FZreconstruct�srRcCs0tt|�}tt|��D]
}|||||<q|Sr�)rrr3r9)rr��	positionsr=rAr.r.r/rP�s
rPc
sVt���}|j��}t�|��}t���fdd�t�|��D��}|��|����S)z�Test if for Hurwitz space specified by (g,dat), pulling back codimension r relations under the source map and pushing forward under the target map gives relations.
    csg|]}t��|�����qSr.)rO�basis_vectorrc�rr+r;r.r/r�
rxz pullpushtest.<locals>.<listcomp>)rr�r,rRrr�r<r��rowsr�rOr�)
r+rr;rfr,r�r�r=rd�pbr.rUr/�pullpushtests


"rXcs�ddlm}|||��ttd|d��}t�|||�}dd�t�|||�D�}dd�t�|d|d|||�D����fdd�|D�}||kS)NrrscSrr.r8�rQZGrrr.r.r/r� r^zcheckintnum.<locals>.<listcomp>cSrr.r8rYr.r.r/r�!r^r%cs g|]���fdd��D��qS)csg|]
}��|�����qSr.)rqr�)rQ�s2)rr�s1r.r/r�"r#z*checkintnum.<locals>.<listcomp>.<listcomp>r.r��rrr�)r[r/r�"rm)r�r�r[r3r#�pairing_matrixr)r+r,r;r�rMZMpixtonr�ZMselfr.r\r/�checkintnums
(r^cs�ttd|d���t������t����fdd�t����D��}t�|d�}t�����}dd�|D�}|D]@���fdd�|D�}t|���D]-}d|d}	t|���D]}
|||
fdkrn|	|||
f||
7}	qX|	�	�swdSqJq8dS)	Nrcs"g|]
}t���|������qSr.rro)r�r+rMr;r.r/r�+r�z#pullandidentify.<locals>.<listcomp>cSrr.r8rYr.r.r/r�/r^cs"g|]
}��|�����d��qSr�)rlr�r9)rQr{)rtr;r.r/r�2r�rFT)
r[r3r#rrr�r6rr�r�)r+r,r;rr)rr r@r?�vecrAr.)r�r+rtrMr;r/�pullandidentify(s&$���r`cCs�d|d||}ddlm}|||�}|||�}|�|�}|�|�}	tt|d|d��}
|D]!}|	D]}||�|
���}
|�|
�|��}|
|ksQdSq5q1dS)Nr%rrsFT)r�r�rDr2r3r�r�r�)r+rgr�r�r�r�ZRdownZRupZstrata_downZ	strata_upZ	fmarkingsZ
class_downZclass_upZintersection_downZintersection_upr.r.r/�pushpullcompat@s 



��racCs�t||�}tt|�g�}|�d�}|��}|�d�}|��}ddlm}	|	||�}
|
�	|�}|D]}|�
|���}
|
�|�||�|�ksHdSq0dS)a�
    Test that delta-pullback composed with delta-pushforward is multiplication with delta-degree
    for classes in R^r(\bar M_{g',b}) on space of quotient curves for Hurwitz data (g, H).

    TESTS::

        sage: from admcycles.admcycles import deltapullpush, HurData
        sage: G = SymmetricGroup(2)
        sage: H = HurData(G,[G[1],G[1],G[0]])
        sage: deltapullpush(2, H, 2)
        True
    rrrsFT)
rr�rjrSr�rrzr�r�rDr�r�r)r+r4r;r�Z
trivGclassZddegrrZ	bmarkingsr�rrr�r,Zclppr.r.r/�
deltapullpushXs





�rbcCs�ddlm}||�}|�|�|�|d���|�|d���}td�td|d�td|d�d|dtd|�d|}||kS)NrrsrM)rCrM)r�r�r>r7r�rrr)r+r�rrr�r�r.r.r/�lambdaintnumcheckzs
.HrccCs�ddlm}|||��|�}d|d�|�g}t|�}|D]}tt|j��}|�|�r3|�	|���qt
t|�}	|	��}
|
�
�|
}|S)a�
    Returns a vector space W over QQ which is the quotient W = V / U, where
    V = space of vectors representing classes in R^r(\Mbar_{g,n}) in a basis
    U = subspace of vectors representing classes supported outside the open subset
    of \Mbar_{g,n} specified by moduli (= 'sm', 'rt', 'ct' or 'tl')
    Thus for v in V, the vector W(v) is the representation of the class represented by v
    in a basis of R^r(M^{moduli}_{g,n}).
    rrsr)r�r�rDrTrr�r�r��vanishesr�rr�	row_space�ambient_vector_space)r+r,r;r~r�r)ZMsmr�r�ZMsmM�Ur�r.r.r/r��s

�
r�r�r�)FFr�)TNr{r�)rFFN)NT)NNNr{r�)r"T)r)Fr{)NNT)rr)�r|rr_�osr�collections.abcr�ImportError�collections�sage.envr�sage.structure.sage_objectr�sage.arith.allrrrr	r
�sage.arith.miscr�sage.groups.perm_gps.permgroupr
�sage.matrix.constructorr�sage.matrix.specialr�sage.combinat.allrrr�sage.misc.cachefuncr�sage.misc.misc_cr�sage.misc.flattenr� sage.modules.free_module_elementr�sage.rings.allrrrr�sage.modules.free_modulerr~rrr �stable_graphr!r"r(r#r$�initializedr+r,r0r/r1r5r6rWr�r�r�r�rsrr�rr�r�r�r�r�rr�r�rrrQrNrSr�rjr�rr�Zfile_cached_function�pathr0Zignore_args_keyZignore_args_filenamerrr1r;rGr�rurWryZrational_vectors_to_pyZpy_to_rational_vectorsrr�r�r	r�r�rr�r�r�r�r.r�rrErr
rrrrrrr�r"r%r&r(r*r.r0r5r=r>r?rJrKrOrRrPrXr^r`rarbrcr�r.r.r.r/�<module>s\�,
j
&
yo<, B
9
 &
iY
 v{KB�

8#4
F#
D
�
:

_5
R
R7
	'1
�
R.!

$
,
(
A
=
@@K
	

;
K

"0


"