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

��cυ�
@szdZddlZddlmZmZddlmZddlmZddl	m
Z
ddlm	Z	ddlm
Z
dd	lmZdd
lmZmZddlmZddlmZmZmZdd
lmZddlmZddlmZddlm Z ddl!m"Z"ddl#m$Z$ddl%m&Z&d1dd�Z'ddddddddedf
dd�Z(dd�Z)d2dd�Z*d3dd �Z+d!d"�Z,ed#d$��Z-d%d&�Z.d4d'd(�Z/d5d)d*�Z0d+d,�Z1d-d.�Z2d6d/d0�Z3dS)7z
Double ramification cycle
�N)�Tautvecttobasis�tautgens)�StableGraph�)�TautologicalRing)�interpolate)�Subsets)�	factorial)�floor�ceil)�prod)�PolynomialRing�QQ�ZZ)�vector)�MPolynomial)�cached_function)�PowerSeriesRing)�bernoulli_polynomial)�exp)�
PartitionsTFcCs�|dur|}t|�}t||�}|durBtt|�d|d|�}t|�|d|d|krftd��t�|||||�}tdd�t�|||t	t
d|d��tj�D��}	|r�t|	|||�}
|r�|�
|
|�S|
S|r�|�|	|�S|	SdS)a�Returns the k-twisted Double ramification cycle in genus g and codimension d
    for the partition Avector of k*(2g-2+n).

    In the notation of [JPPZ17]_, the output is 2^(-d) * P_g^{d,k}(Avector).

    Note: This is based on the old implementation DR_compute by Pixton. A new one,
    which can be faster in many examples is DR_cycle.

    INPUT:

    - ``tautout`` -- bool (default: `True`); if False, returns a vector
      (in all generators for basis=false, in the basis of the ring for basis=true)

    - ``basis``   -- bool (default: `False`); if True, use FZ relations to give out the
      DR cycle in a basis of the tautological ring
    N��12g-2+n must divide the sum of entries of Avector.cSsg|]}t|��qS��r)�.0�arr�G/home/user/Introduction lectures/admcycles/double_ramification_cycle.py�
<listcomp>=�z DR_cycle_old.<locals>.<listcomp>r)�lenrr
�sum�
ValueError�DR�
DR_computer� convert_vector_to_monomial_basis�tuple�range�	MODULI_STr�from_basis_vector�from_vector)�g�Avector�d�k�tautout�basis�n�R�v�v1�v2rrr�DR_cycle_old"s$
0r6�stcsv�dur��t���tdd��D��r�t��������}t���d|d�|	�	d�	\}
���fdd�t��D��
|
��
fd	d
��}
|r�t��|	|d�}|�	|
��S|
S�	r�tdd��D��r�t
d
��t��}�du�r@|d�d�dkr�t
d���du�rt|d�d���t���d�d�k�r�t
d��nt�du�r�|d�d�dk�r~t|d�d���nt
d��t����d�d��k�r�t
d���	�rЈddk�r�t
d��t��|	|
d�}t
���d|	d��t���������	f	dd��D��}��s2|dtd��9}|�r\t|����}|�rX|�|��S|S|�rn|�	|��S|SdS)uy%Returns the k-twisted Double ramification cycle in genus g and codimension d
    for the partition Avector of k*(2g-2+n). If some elements of Avector are elements of a
    polynomial ring, compute DR-polynomial and substitute the entries of Avector - the result
    then has coefficients in a polynomial ring.

    In the notation of [JPPZ17]_, the output is 2^(-d) * P_g^{d,k}(Avector).

    Note: This is a reimplementation of Pixton's DR_compute which can be faster in many examples.
    To access the old version, use DR_cycle_old - it might be faster on older SageMath-versions.

    INPUT:

    - ``rpoly``  -- bool (default: `False`); if True, return tautclass 2^(-d) * P_g^{d,r,k}(Avector)
      whose coefficients are polynomials in the variable r (for r>>0).

    - ``tautout`` -- bool (default: `True`); if False, returns a vector
      (in all generators for basis=false, in the basis of the ring for basis=true)

    - ``basis``   -- bool (default: `False`); if True, use FZ relations to give out the
      DR cycle in a basis of the tautological ring

    - ``chiodo_coeff`` -- bool (default: `False`); if True, return the formula
      r^(2d-2g+1) epsilon_* c_d(-R* pi_* \L) from [JPPZ17]_, Corollary 4, Proposition 5 instead.
      It has DR_cycle(g, Avector) as its r=0 specialization.

    - ``r_coeff`` -- integer or None (default: `None`); if an integer ``r0`` is given, return
      the class/vector 2^(-d) * P_g^{d,r0,k}(Avector) for this fixed ``r0``. This option is
      incompatible with ``rpoly = True`` or polynomial entries of ``Àvector``.
      For r0>>0 this will agree with the value of the polynomial-coefficient class from
      ``rpoly = True`` at ``r=r0`` above.

    - ``moduli`` -- string (default: `'st'`); moduli on which DR is computed

    - ``base_ring`` -- string (default: `QQ`); ring of coefficients of the DR-cycle

    - ``spin`` -- bool (default: `False`); if True, compute the spin DR-cycle, and
      the input ramification data has to be odd numbers

    EXAMPLES::

      sage: from admcycles import DR_cycle, DR_cycle_old
      sage: DR_cycle(1, (2, 3, -5))
      Graph :      [1] [[1, 2, 3]] []
      Polynomial : 2*psi_1 + 9/2*psi_2 + 25/2*psi_3
      <BLANKLINE>
      Graph :      [0] [[5, 6, 1, 2, 3]] [(5, 6)]
      Polynomial : -1/24
      <BLANKLINE>
      Graph :      [0, 1] [[1, 2, 5], [3, 6]] [(5, 6)]
      Polynomial : -25/2
      <BLANKLINE>
      Graph :      [0, 1] [[1, 3, 5], [2, 6]] [(5, 6)]
      Polynomial : -9/2
      <BLANKLINE>
      Graph :      [0, 1] [[2, 3, 5], [1, 6]] [(5, 6)]
      Polynomial : -2
      sage: DR_cycle(1, (2, 3, -5), moduli='ct')
      Graph :      [1] [[1, 2, 3]] []
      Polynomial : 2*psi_1 + 9/2*psi_2 + 25/2*psi_3
      <BLANKLINE>
      Graph :      [0, 1] [[1, 2, 5], [3, 6]] [(5, 6)]
      Polynomial : -25/2
      <BLANKLINE>
      Graph :      [0, 1] [[1, 3, 5], [2, 6]] [(5, 6)]
      Polynomial : -9/2
      <BLANKLINE>
      Graph :      [0, 1] [[2, 3, 5], [1, 6]] [(5, 6)]
      Polynomial : -2
      sage: DR_cycle(1, (2, 3, -5), moduli='sm')
      0

    Here we check that `P_g^{d,k}(Avector)=0` for `d>g` ([CJ18]_)::

      sage: D = DR_cycle(1, (1, 3, -4), d=2)
      sage: D2 = DR_cycle_old(1, (1, 3, -4), d=2)  # long time
      sage: D.vector() == D2.vector()              # long time
      True
      sage: D.is_zero()
      True
      sage: v = DR_cycle(2, (3,), d=4, rpoly=true).evaluate()
      sage: v  # Conjecture by Longting Wu predicts that r^1-term vanishes
      -1/1728*r^6 + 1/576*r^5 + 37/34560*r^4 - 13/6912*r^3 - 1/1152*r^2

    Using ``chiodo_coeff = True`` we can compute the more complicated formula for
    the DR_cycle appearing in the original proof in [JPPZ17]_. It should give the same
    result when ``rpoly = False``, but as a polynomial in r it will differ from the
    simplified formula::

      sage: g=2; A=(2,4,-1); d=2; k=1
      sage: v1 = DR_cycle(g,A,d,k,chiodo_coeff=True).vector()
      sage: v2 = DR_cycle(g,A,d,k,chiodo_coeff=False).vector()
      sage: v1 == v2
      True
      sage: g=1; A=(1,5); d=1; k=3
      sage: DR_cycle(g,A,d,k,rpoly=True, chiodo_coeff=True)
      Graph :      [1] [[1, 2]] []
      Polynomial : (-1/12*r^2 + 3/2*r - 9/2)*(kappa_1)_0 + (1/12*r^2 - 1/2*r + 1/2)*psi_1 + (1/12*r^2 - 5/2*r + 25/2)*psi_2
      <BLANKLINE>
      Graph :      [0] [[4, 5, 1, 2]] [(4, 5)]
      Polynomial : -1/24
      <BLANKLINE>
      Graph :      [0, 1] [[1, 2, 4], [5]] [(4, 5)]
      Polynomial : -1/12*r^2 + 3/2*r - 9/2

    Setting ``r_coeff`` to a specific value, we can compute the class
    2^(-d) * P_g^{d,r0,k}(Avector) even in the non-polynomial regime, both with
    ``chiodo_coeff`` being ``True`` or ``False``::

      sage: g=2; A=(5,-1); d=2; k=1
      sage: D2 = DR_cycle(g,A,tautout=False,r_coeff=7)
      sage: D7 = DR_cycle(g,A,tautout=False,r_coeff=7)
      sage: Dr = DR_cycle(g,A,tautout=False,rpoly=True)
      sage: r = Dr.parent().base().gens()[0]  # extract coefficient variable r
      sage: Dr.subs({r:2}) == D2  # r=2 not in polynomial regime
      False
      sage: Dr.subs({r:7}) == D7  # r=7 is in polynomial regime
      True

    We can create a polynomial ring and use an Avector with entries in this ring.
    The result is a tautological class with polynomial coefficients::

      sage: R.<a1,a2>=PolynomialRing(QQ,2)
      sage: Q=DR_cycle(1,(a1,a2,-a1-a2))
      sage: Q
      Graph :      [1] [[1, 2, 3]] []
      Polynomial : 1/2*a1^2*psi_1 + 1/2*a2^2*psi_2 + (1/2*a1^2 + a1*a2 + 1/2*a2^2)*psi_3
      <BLANKLINE>
      Graph :      [0] [[5, 6, 1, 2, 3]] [(5, 6)]
      Polynomial : -1/24
      <BLANKLINE>
      Graph :      [0, 1] [[1, 2, 5], [3, 6]] [(5, 6)]
      Polynomial : -1/2*a1^2 - a1*a2 - 1/2*a2^2
      <BLANKLINE>
      Graph :      [0, 1] [[1, 3, 5], [2, 6]] [(5, 6)]
      Polynomial : -1/2*a2^2
      <BLANKLINE>
      Graph :      [0, 1] [[2, 3, 5], [1, 6]] [(5, 6)]
      Polynomial : -1/2*a1^2

    We can compute the spin DR cycle as constructed in [Costantini-Sauvaget-Schmitt-21]::

      sage: spinDR=DR_cycle(2,(9,-3,-1),spin=True)
      sage: spinDR.basis_vector()
      (-367, 122, -117, -372, -319, 28, 405, 268, 841, 397, 709, 427, -600, -923, 216, -422, -388, 285, -370, -612, 850, 364, -850, 243/2, 16, -227/2, -243/2, -122, -49, 89/2, 168, 26, -125/2, -48, 10, -45/2, 76, 24, -35/2, 79, -207/2, -31, -90, 195/2)

    We can compute the spin DR as a polynomial::

      sage: R.<a>=PolynomialRing(QQ,1)
      sage: DR_cycle(1,(2*a+1,-2*a+1),spin=True)
      Graph :      [1] [[1, 2]] []
      Polynomial : -1/4*(kappa_1)_0 + (a^2 + a + 1/4)*psi_1 + (a^2 - a + 1/4)*psi_2
      <BLANKLINE>
      Graph :      [0] [[4, 5, 1, 2]] [(4, 5)]
      Polynomial : 1/24
      <BLANKLINE>
      Graph :      [0, 1] [[1, 2, 4], [5]] [(4, 5)]
      Polynomial : -1/4

    This can be used to check Theorem 1.4 in [CSS21]_ for g=2, n=2::

        sage: g=2; n=2
        sage: from admcycles import psiclass
        sage: T = PolynomialRing(QQ,n,'a')
        sage: avec = T.gens()
        sage: k = sum(avec)/(2*g-2+n)
        sage: R.<z> = PowerSeriesRing(T, default_prec = 2*g+10)
        sage: cosh = 1/2*(exp(z)+exp(-z))
        sage: sinh = 1/2*(exp(z)-exp(-z))
        sage: S = sinh(z/2)/(z/2)
        sage: Sprime = S.derivative()
        sage: helpfun = exp(avec[0]*z*Sprime(k*z)/S(k*z))*cosh(z/2)/S(z)*prod(S(avec[i]*z) for i in range(1,n))/S(k*z)**(2*g+n-1)
        sage: 2**(-g)*helpfun[2*g]
        23/5898240*a0^4 - 29/1474560*a0^3*a1 + 157/2949120*a0^2*a1^2 - 53/1474560*a0*a1^3 + 103/5898240*a1^4 + 1/6144*a0^2 - 1/9216*a0*a1 + 11/18432*a1^2 - 1/2880
        sage: a0, a1 = T.gens()
        sage: (DR_cycle(g,(a0, a1), chiodo_coeff=True, spin=True)*psiclass(1,2,2)^(2*g-3+n)).evaluate()
        23/5898240*a0^4 - 29/1474560*a0^3*a1 + 157/2949120*a0^2*a1^2 - 53/1474560*a0*a1^3 + 103/5898240*a1^4 + 1/6144*a0^2 - 1/9216*a0*a1 + 11/18432*a1^2 - 1/2880

    TESTS::

      sage: from admcycles import DR_cycle, DR_cycle_old
      sage: D = DR_cycle(2, (3, 4, -2), k=1)       # long time
      sage: D2 = DR_cycle_old(2, (3, 4, -2), k=1)  # long time
      sage: D.vector() == D2.vector()              # long time
      True
      sage: D = DR_cycle(2, (1, 4, 5), k=2)        # long time
      sage: D2 = DR_cycle_old(2, (1, 4, 5), k=2)   # long time
      sage: D.vector() == D2.vector()              # long time
      True
      sage: D = DR_cycle(3, (2,4), k=1)            # long time
      sage: D2 = DR_cycle_old(3, (2,4), k=1)       # long time
      sage: D.vector() == D2.vector()              # long time
      True

      sage: D = DR_cycle(2, (3,),tautout=False); D
      (0, 1/8, -9/4, 81/8, 1/4, -9/4, -1/8, 1/8, 1/4, -1/8, 1/48, 1/240, -3/16, -41/240, 1/48, 1/48, 1/1152)
      sage: D2=DR_cycle_old(2, (3,), tautout=False); D2
      (0, 1/8, -9/4, 81/8, 1/4, -9/4, -1/8, 1/8, 1/4, -1/8, 1/48, 1/240, -3/16, -41/240, 1/48, 1/48, 1/1152)
      sage: D3 = DR_cycle(2, (3,), tautout=False, basis=True); D3
      (-5, 2, -8, 18, 3/2)
      sage: D4 = DR_cycle_old(2, (3,), tautout=False, basis=True); D4
      (-5, 2, -8, 18, 3/2)

      sage: g=3; A=(5,8,1); d=1; k=2
      sage: D1 = DR_cycle(g,A,d,k,chiodo_coeff=True)
      sage: D2 = DR_cycle(g,A,d,k,chiodo_coeff=False)
      sage: D1.vector() == D2.vector()
      True

      sage: g=2; A=(6,); d=2; k=2
      sage: D8 = DR_cycle(g,A,tautout=False,chiodo_coeff=True,r_coeff=8)
      sage: Dr = DR_cycle(g,A,tautout=False,chiodo_coeff=True,rpoly=True)
      sage: r = Dr.parent().base().gens()[0]  # extract coefficient variable r
      sage: Dr.subs({r:8}) == D8
      True

    Ncss|]}t|t�VqdS�N)�
isinstancer)r�airrr�	<genexpr>-rzDR_cycle.<locals>.<genexpr>FT)r/r0�gensout�chiodo_coeff�moduli�spincsi|]}�|�|�qSrr�r�i)r,�gensrr�
<dictcomp>3rzDR_cycle.<locals>.<dictcomp>cs
|���Sr8)�subs)�x)�subsdictrr�<lambda>4rzDR_cycle.<locals>.<lambda>)r>�	base_ringcss|]}|ddkVqdS�rrNr�rrErrrr;<rz*The ramification data is not of spin type.rrrz.The entries of Avector must sum to k*(2g-2+n).zFIf a value of r_coeff is specified, the parameter k must be specified.z:The entries of Avector must sum to k*(2g-2+n) mod r_coeff.rz(The integer k has to be odd for spin DR.)rH)�decstr>cs(g|] }t|���������d�
�qS))r?)�DR_coeff_new)r�decs)	r,r=r-r+r.r1�r_coeff�rpolyr?rrrVrzDR_cycle.<locals>.<listcomp>)r �anyr�parentrH�DRpolyr'�	apply_maprr*r"r!r
rrrr))r+r,r-r.rOr/r0r=rNr>rHr?�BR�polr2ZAsumr3r4r)r,r=r-r+rBr.r1rNrOr?rFr�DR_cyclePs`Z�




&&rVcs.|j�|jjd\}}g}	g}
|rLttdd�}|��\��|��|��}ntd|��f�}��fdd�t�j	�D�}
t
����D]j}|r�|t���fdd�t||�D��9}q�t
||�dkr�|�d||dt||d�9}q�t
d|d�D]������}|��d�}|
|��d7<|�r�td�}t|�D]2}|��}|t����fd	d�t|�D��7}�qD||9}q�|��dd|t|�9}q��jD]v\}}|�|d�}|�|d�}|	�||d�|
�||g�|�r�n,|d
||t|�t|�||d9}�q�|	|
||
fS)Nrzx,rrrcs0g|](\}}�d|dt�j|��qS�r)r �_legs)rrA�gv)�gammar.rrrrs�z"DR_coeff_setup.<locals>.<listcomp>c3sR|]J\}}d|dt�|d�����|d|d|t|�VqdS)�����rrN�rr	�r�m�ex)r.�rrErrr;xs�"����z!DR_coeff_setup.<locals>.<genexpr>c3sV|]N\}}d|t�|d���d���|d|d|t|�VqdS�r[rrNr\r])r,rAr`rErrr;�s������r[)rZ�poly�monomr
rrB�one�automorphism_number�	enumerate�_generar'�	num_vertsrr r	�vertex�getr�to_exp�_edges�append)�Gr+r1r-r,r.r=�kappa�psi�exp_list�
exp_list_finer2�
scalar_factor�
given_weightsr3ZpsipowZ	sfcontrib�parZparexp�lu�lvZpsipowuZpsipowvr)r,rZrAr.r`rEr�DR_coeff_setupgsZ�
�,
�
"�
�
rxc
Csn|j}
|jjd\}}|s0tdd�|D��r0dSttdd�|D��td��|t|�}
|
��|
�	�d}t
|||||||�\}}}}|r�d|}ndt|�}|dur�|dt|�8<|
�|�}|
��}|dur�d}|d}
|	�rt
d�t
d||�}nt
d�}|t|||||
d|||||||	�}|�rL|�rD|S||S|�r^|jdd�S|jdd�|S)	Nrcss|]}t|�dkVqdS�rN)r )rZkalistrrrr;�rzDR_coeff_new.<locals>.<genexpr>cSsg|]}t|��qSr)�absr@rrrr�rz DR_coeff_new.<locals>.<listcomp>rr)r`)rZrbrcrPrr!rrz�	num_edgesrhrx�
flow_solve�cycle_basisr�
mpoly_specialrD)rnr+r1r-r,r.rOr=rNr?rZro�_�m0�h0rqrtrsrr�deg�u�VbasisZspin_factor�mpolyrrrrL�s8*

&rLcs�tt|||d��}|r4|dur4|�||d�|rFdd�|D�}g}
t��}t|�}|D�]�d}tj�fdd�t|�D��D]��|t��fdd�t|�D����fdd��D��|r�|r�td	d
��D��r�|t���fdd
�t|�D��7}q�|�rtdd
��D��r�|t���fd
d�t|�D��7}q�|�r`|
�|d��|�d|
|�q^|
�|t	�|��q^t
||
d�}|��|k�r�td��|S)a,
    Return the sum of the rational function in DR_coeff_new over the
    affine space u + V modulo r in ZZ^n as a univariate polynomial in r.
    V is the lattice with basis Vbasis.
    Use that this sum is polynomial in r starting from r=start and the polynomial has
    degree degr (for now).
    rNcSsg|]}d|�qSrWr)r�qrrrr�rz!mpoly_special.<locals>.<listcomp>rcsg|]}tt����qSr��listr'r@�r^rrr�rcsg|]}�|�|�qSrrr@�r��coeffrrr�rcsg|]}|��qSrr�r�vir�rrr�rcss|]}|ddkVqdSrIrrJrrrr;�rz mpoly_special.<locals>.<genexpr>c3s6|].}t�|d�|d�|���VqdS)rrN)�econtribr@)rrr^r3rrr;�rcss|]}|ddkVqdSrIrrJrrrr;�rcs(g|] }�|��|�|�qSrrr@)rqr^r3rrr�rrr`z0Polynomial has higher degree in r than expected!)
r�r'rmr �	itertools�productr!�allrrr�degreer")rqr�r�r��start�degrr=rNrsrrr-r?�mrange�mvalues�rankZulen�total�resultr)r�r�rqrrr^r3rr~�s2
  $$&r~cs8t||�||f}|��fdd�t||d�D��S)Nc3s<|]4}d|t�t��|d�|d|dVqdSra)rr)rr^�r`�w1rrr;�rzecontrib.<locals>.<genexpr>r)�edge_power_seriesr')�e1�e2r�r`Z	polycoeffrr�rr��sr�cs�ttd|d�}|���t|d|dd�}|��\��t���fdd�t|d�D��}dt|���}dd	�|����D�S)
NrrzX,Yr)�default_precc3s0|](}�|�|d�|dVqdSryrr@��A�X�Yrrr;rz$edge_power_series.<locals>.<genexpr>cSsi|]\}}t|�|�qSr)r&)rr.�itrrrrCrz%edge_power_series.<locals>.<dictcomp>)	r
rrBrr!r'r�dict�items)r�r2�Sr_�hrr�rr�s"r�c
s�tt|||d��}g}t��}|D]z�d}tj�fdd�t|�D��D]J�|t��fdd�t|�D��}	�fdd�|	D�}	||�g|	�R�7}qJ|�|�q&t||d�S)a3
    Return the sum of the polynomial P in variables r, d1, ..., dn over the
    affine space u + V modulo r in ZZ^n as a univariate polynomial in r.
    V is the lattice with basis Vbasis.
    Use that this sum is polynomial in r starting from r=start and the polynomial has
    degree degr (for now).
    rrcsg|]}tt����qSrr�r@r�rrrrz$mpoly_affine_sum.<locals>.<listcomp>csg|]}�|�|�qSrrr@r�rrrrcsg|]}|��qSrrr�r�rrrrr`)r�r'r r�r�r!rmr)
�Pr�r�r�r�r�r�r�r�r3r)r�r�r^r�mpoly_affine_sums  r�c
sd|durttd|�}�dur$|���|dkr:|��|�Stt�d��g|}tj|�}	�dur|��fdd�t|�D��n���fdd�t|�D��d}
|	D]��t�����fdd�t|�D��}���fd	d�t|�D��|�	��fd
d�t|�D��}�du�r�fdd��D��|dk�rJ||�|
t
�fd
d�|��D��7}
q�|
|��||7}
q�|
S)azTakes a vector/number-valued function f on n variables and interpolates it on a grid around 0.
    Returns a vector with entries in a polynomial ring.

    INPUT:

    - ``d``        -- integer; maximal degree of output-polynomial in any of the variables

    - ``gridwidth``-- integer (default: `1`); width of the grid used for interpolation

    - ``R``        -- polynomial ring (default: `None`); expected to be polynomial ring in
      at least n variables; if None, use ring over QQ in variables z0,...,z(n-1)

    - ``generator``-- list (default: `None`); list of n variables in the above polynomial
      ring to be used in output; if None, use first n generators of ring

    - ``enlarge``-- integer (default: `1`); the factor of enlarging the gridwidth during
      interpolating the values

    - ``gridshift``-- tuple (default: `None`); of length n to shift the
      grid before interpolation takes place

    - ``transf_poly``-- polynomial (default: `None`); a polynomial of single variable of how to
      modify the input values to the function

    EXAMPLES::

        sage: from admcycles.double_ramification_cycle import multivariate_interpolate
        sage: from sage.modules.free_module_element import vector
        sage: def foo(x,y):
        ....:     return vector((x**2+y,2*x*y))
        ....:
        sage: multivariate_interpolate(foo,2,2)
        (z0^2 + z1, 2*z0*z1)
    N�zrrcs&g|]}t�dtd����qS�rr�r
rr@)r-�	gridwidthrrrXrz,multivariate_interpolate.<locals>.<listcomp>cs,g|]$}�|t�dtd����qSr�r�r@)r-�	gridshiftr�rrrZrcs2g|]*�t�����fdd�t�d�D���qS)cs0g|](}|��kr��|����qSrr)r�j)�	generatorr�rA�p�shiftrrr_s�z7multivariate_interpolate.<locals>.<listcomp>.<listcomp>r)rr'�r)r-r�r�r�r�)rArr_s�
�cs g|]}��|�|�qSrrr@)r�r�r�rrrbrcsi|]}�|�|�qSrrr@)r��pvalrrrCcrz,multivariate_interpolate.<locals>.<dictcomp>csg|]}�|��qSrr)r�val)�transf_polyrrrerc3s|]}|�VqdSr8r)r�e)�multrrr;mrz+multivariate_interpolate.<locals>.<genexpr>)r
rrBrdr�r'r�r�rrDr)
�fr-r1r�r2r�r�r��cube�pointsr�Zlagr�valuer)	r-r�r�r�r�r�r�r�r�r�multivariate_interpolate(s2#
�

 r�c
sR�����fdd�}|dur:ttdd�td|d�D��}�durR|��d|��t�|��}
d�d|}�r�t�d|gd	d�t|d�D��}ttd
d�}d|��dd}t|d�||||�||d�}|��fdd
�t|�D��}nt|d�||||�d�}|�s |}n ��s4|
�|��}n|
�	|��}|�rN|�fS|S)a�

    Return the Double ramification cycle in genus g with n markings in degree d as a
    tautclass with polynomial coefficients. Evaluated at a point (a_1, ..., a_n) with
    sum a_i = k(2g-2+n) it equals DR_cycle(g,(a_1, ..., a_n),d).

    The computation uses interpolation and the fact that DR is a polynomial in the a_i
    of degree 2*d.

    INPUT:

    - ``dplus``  -- integer (default: `0`); if dplus>0, the interpolation is performed
      on a larger grid as a consistency check

    - ``tautout``-- bool (default: `True`); if False, returns a polynomial-valued vector
      (in all generators for basis=false, in the basis of the ring for basis=true)

    - ``basis``  -- bool (default: `False`); if True, use FZ relations to give out the
      DR cycle in a basis of the tautological ring

    - ``ring``   -- polynomial ring (default: `None`); expected to be polynomial ring in
      at least n variables; if None, use ring over QQ in variables a1,...,an

    - ``gens``   -- list (default: `None`); list of n variables in the above polynomial
      ring to be used in output; if None, use first n generators of ring

    - ``gensout``-- bool (default: `False`); if True, return (DR polynomial, list of generators
      of coefficient ring)

    - ``spin``-- bool (default: False`); if True, return the spin DR polynomial

    EXAMPLES::

      sage: from admcycles import DRpoly, DR_cycle, TautologicalRing
      sage: R = TautologicalRing(1, 2)
      sage: D, (a1, a2) = DRpoly(1, 1, 2, gensout=True)
      sage: D = D.subs({a2:-a1})
      sage: D = D.simplify()
      sage: D
      Graph :      [1] [[1, 2]] []
      Polynomial : 1/2*a1^2*psi_1 + 1/2*a1^2*psi_2
      <BLANKLINE>
      Graph :      [0] [[4, 5, 1, 2]] [(4, 5)]
      Polynomial : -1/24
      sage: (D*R.psi(1)).evaluate() # intersection number with psi_1
      1/24*a1^2 - 1/24
      sage: (D.subs({a1:4})-DR_cycle(1,(4,-4))).is_zero() # polynomial agrees with DR_cycle at (4,-4)
      True

     DR vanishes in degree d>g ([CJ18]_)::

      sage: DRpoly(1,2,2).is_zero()
      True
      sage: DRpoly(1,1,2,moduli='ct')
      Graph :      [1] [[1, 2]] []
      Polynomial : (-1/8*a1^2 - 1/4*a1*a2 - 1/8*a2^2)*(kappa_1)_0 + 1/2*a1^2*psi_1 + 1/2*a2^2*psi_2
      <BLANKLINE>
      Graph :      [0, 1] [[1, 2, 4], [5]] [(4, 5)]
      Polynomial : -1/8*a1^2 - 1/4*a1*a2 - 1/8*a2^2
      sage: R.<a1,a2,a3,b1,b2,b3> = PolynomialRing(QQ, 6)
      sage: Da = DRpoly(1, 1, 3, ring=R, gens=[a1, a2, a3])
      sage: Db = Da.subs({a1:b1, a2:b2, a3:b3})
      sage: Dab = Da.subs({a1:a1+b1, a2:a2+b2, a3:a3+b3})
      sage: diff = Da*Db - Da*Dab    # this should vanish in compact type by [HoPiSc19]_
      sage: diff.is_zero()
      False
      sage: diff.is_zero(moduli='ct')
      True
    c	st�|�d���d�S)NF)r/r0r>r?)rV)r,)r0r-r+r>r?rrr��szDRpoly.<locals>.fNcSsg|]}d|�qS)za%srr@rrrr�rzDRpoly.<locals>.<listcomp>rrrcSsg|]}d�qS)r[rr@rrrr�rrE)r2r�r�r�cs.i|]&}�|td�d�|td��qSr�rr@)rBrrrC�rzDRpoly.<locals>.<dictcomp>)r2r�)
r
rr'rBrr&r�rDr*r))r+r-r1Zdplusr/r0�ringrBr<r=r>r?r�r2r�ZshiftvecZR_transfr��interp�ansr)r0r-r+rBr>r?rrRss,E( rRcCsJg}|D]8}d}|D] \}}|��|kr|||7}q|�|�qt|�S)a�Takes a vector of polynomials in several variables and returns a vector containing the (total)
    degree d part of these polynomials.

    INPUT:

    - vector of polynomials

    - integer degree

    EXAMPLES::

        sage: from admcycles.double_ramification_cycle import degree_filter
        sage: R.<x,y> = PolynomialRing(QQ, 2)
        sage: v = vector((x+y**2+2*x*y,1+x**3+x*y))
        sage: degree_filter(v, 2)
        (2*x*y + y^2, x*y)
    r)r�rmr)Zpolyvecr-Z	resultvec�pi�s�cr^rrr�
degree_filter�sr�csPt���t�������fdd��t���fdd�t�d�D��}td�|S)ab
    Returns a divisor class D extending the pullback of the theta-divisor under the Abel-Jacobi map (on compact type) given by partition A of zero.

    Note: D^g/g! agrees with the Double-Ramification cycle in compact type.

    EXAMPLES::

      sage: from admcycles import *

      sage: R = PolynomialRing(QQ, 'z', 3)
      sage: z0, z1, z2 = R.gens()
      sage: u = Hain_divisor(2, (z0, z1, z2))
      sage: g = DRpoly(2, 1, 3, ring=R, gens=[z0, z1, z2]) #u,g should agree inside compact type
      sage: (u.vector() - g.vector()).subs({z0: -z1-z2})
      (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1/24)
    cst|�}|dkr0t|�dkr0��t|�d�S|�krrt|��dkrrttd�d��|}��t|�d�S|dkr�t|�dks�|�kr�t|��kr����Sttd�d��|}t|�|gt|��dgt|��dgg�d�dfg�}td|��f��|�S)Nrrr)	�setr rpr�r'�zerorrre)�l�IZi_setZIcompZgra)r2r+r1rr�delt
s(.�zHain_divisor.<locals>.deltc
s8g|]0�t���fdd�tttd�d���D���qS)cs0g|](}t�fdd�|D��d��|��qS)csg|]}�|d�qS�rrr@)r�rrrrz6Hain_divisor.<locals>.<listcomp>.<listcomp>.<listcomp>r)r!)rr�)r�r�r�rrrs�z+Hain_divisor.<locals>.<listcomp>.<listcomp>r)r!rr�r'r�)r�r�r1)r�rrs��z Hain_divisor.<locals>.<listcomp>r)r[�)r rr!r'r)r+r�r�r)r�r2r�r+r1r�Hain_divisor�s

�r�c
Cs�td�}td�}td�|d|}td�}|d}td�|d||d|d|d||t||||d||d�S)a)
    Return the class Theta_{g,n} from the paper [Nor]_ by Norbury.

    INPUT:

    - ``moduli`` -- string (default: `'st'`); moduli on which Theta_{g,n} is computed

    EXAMPLES::

        We can verify many of the general properties of Theta_{g,n} in examples, starting
        with the initial condition Theta_{1,1} = 3 * psi_{1,1}.

            sage: from admcycles import ThetaClass, TautologicalRing
            sage: R = TautologicalRing(1, 1)
            sage: (ThetaClass(1,1) - 3*R.psi(1)).is_zero()
            True

        Likewise, we can check that the Theta-class pulls back correctly under boundary
        gluing maps.

            sage: from admcycles.admcycles import StableGraph, prodtautclass
            sage: A = ThetaClass(3,0)
            sage: gamma1 = StableGraph([1,2],[[1],[2]],[(1,2)])
            sage: pb1 = gamma1.boundary_pullback(A)
            sage: pb1.totensorTautbasis(4)
            [[0], [   207 -189/2   27/2], [], [], []]
            sage: check1 = prodtautclass(gamma1, protaut = [ThetaClass(1,1), ThetaClass(2,1)])
            sage: check1.totensorTautbasis(4)
            [[0], [   207 -189/2   27/2], [], [], []]

        A similar pullback property holds for the gluing map associated to the
        divisor of irreducible nodal curves.

            sage: B = ThetaClass(2,1)
            sage: gamma2 = StableGraph([1],[[1,2,3]],[(2,3)])
            sage: pb2 = gamma2.boundary_pullback(B)
            sage: pb2.totensorTautbasis(3)
            (6)
            sage: ThetaClass(1,3).basis_vector()
            (6)

        Finally, we check the property Theta_{g,n+1} = pi*(Theta_{g,n}) * psiclass_{n+1}::

            sage: C = ThetaClass(2,0)
            sage: R = TautologicalRing(2, 1)
            sage: (C.forgetful_pullback([1]) * R.psi(1) - B).is_zero()
            True
    rrr�T)r=rNr>)rrV)r+r1r>r`r�r-rEr�rrr�
ThetaClass#s1

r�)NNTF)F)F)rNNNN)	rTFNNFFr7F)r7)4�__doc__r�Zadmcycles.admcyclesrrZadmcycles.stable_graphr�tautological_ringrr#rZadmcycles.DR�sage.combinat.subsetr�sage.arith.allr	�sage.functions.otherr
r�sage.misc.misc_cr�sage.rings.allr
rr� sage.modules.free_module_elementr�.sage.rings.polynomial.multi_polynomial_elementr�sage.misc.cachefuncr�sage.rings.power_series_ringr�sage.combinat.combinatr�sage.functions.logr�sage.combinat.partitionrr6rVrxrLr~r�r�r�r�rRr�r�r�rrrr�<module>sD	
.5
8
'


K
g-