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

��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*d2dd �Z+d!d"�Z,ed#d$��Z-d%d&�Z.d3d'd(�Z/d4d)d*�Z0d+d,�Z1d-d.�Z2d5d/d0�Z3dS)6z
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||�}|dur!tt|�d|d|�}t|�|d|d|kr3td��t�|||||�}tdd�t�|||t	t
d|d��tj�D��}	|rgt|	|||�}
|re|�
|
|�S|
S|ro|�|	|�S|	S)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.cS�g|]}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r7�stcsb�dur��t���tdd��D��rSt��������}t���d|d�|	�	d�	\}
���fdd�t��D��
|
��
fd	d
��}
|rQt��|	|d�}|�	|
��S|
S�	rbtdd��D��rbt
d
��t��}�dur�|d�d�dkrzt
d���dur�t|d�d���t���d�d�kr�t
d��n7�dur�|d�d�dkr�t|d�d���nt
d��t����d�d��kr�t
d���	r��ddkr�t
d��t��|	|
d�}t
���d|	d��t���������	f	dd��D��}��s|dtd��9}|�r&t|����}|�r$|�|��S|S|�r/|�	|��S|S)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>-s�zDR_cycle.<locals>.<genexpr>FT)r0r1�gensout�chiodo_coeff�moduli�spincsi|]	}�|�|�qSrr�r�i)r-�gensrr�
<dictcomp>3�zDR_cycle.<locals>.<dictcomp>cs
|���Sr9)�subs)�x)�subsdictrr�<lambda>4s
zDR_cycle.<locals>.<lambda>)r?�	base_ringcss�|]	}|ddkVqdS�rrNr�rrGrrrr<<��z*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.)rJ)�decstr?cs(g|]}t|���������d�
�qS))r@)�DR_coeff_new)r�decs)	r-r>r.r,r/r2�r_coeff�rpolyr@rrrV�(zDR_cycle.<locals>.<listcomp>)r!�anyr�parentrJ�DRpolyr(�	apply_maprr+r#r"r
rrrr*)r,r-r.r/rRr0r1r>rQr?rJr@�BR�polr3ZAsumr4r5r)r-r>r.r,rCr/r2rQrRr@rHr�DR_cyclePsbZ
��$&rZcs&|j�|jjd\}}g}	g}
|r&ttdd�}|��\��|��|��}ntd|��f�}��fdd�t�j	�D�}
t
����D]5}|rY|t���fdd�t||�D��9}qAt
||�dkrv|�d||dt||d�9}qAt
d|d�D]Q�����}|��d�}|
|��d7<|r�td�}t|�D]}|��}|t����fd	d�t|�D��7}q�||9}q~|��dd|t|�9}q~�jD]9\}}|�|d�}|�|d�}|	�||d�|
�||g�|r�q�|d
||t|�t|�||d9}q�|	|
||
fS)Nrzx,rrrcs0g|]\}}�d|dt�j|��qS�r)r!�_legs)rrB�gv)�gammar/rrrrs$�z"DR_coeff_setup.<locals>.<listcomp>c3sT�|]%\}}d|dt�|d�����|d|d|t|�VqdS)�����rrN�rr	�r�m�ex)r/�rrGrrr<xs�"�����z!DR_coeff_setup.<locals>.<genexpr>c3sX�|]'\}}d|t�|d���d���|d|d|t|�VqdS�r_rrNr`ra)r-rBrdrGrrr<�s�������r_)r^�poly�monomr
rrC�one�automorphism_number�	enumerate�_generar(�	num_vertsrr!r	�vertex�getr�to_exp�_edges�append)�Gr,r2r.r-r/r>�kappa�psi�exp_list�
exp_list_finer3�
scalar_factor�
given_weightsr4ZpsipowZ	sfcontrib�parZparexp�lu�lvZpsipowuZpsipowvr)r-r^rBr/rdrGr�DR_coeff_setupgs\�
�*�
�
"�
�r|c
Csf|j}
|jjd\}}|stdd�|D��rdSttdd�|D��td��|t|�}
|
��|
�	�d}t
|||||||�\}}}}|rLd|}ndt|�}|dur`|dt|�8<|
�|�}|
��}|dursd}|d}
|	r�t
d�t
d||�}nt
d�}|t|||||
d|||||||	�}|r�|r�|S||S|r�|jdd�S|jdd�|S)	Nrcss�|]	}t|�dkVqdS�rN)r!)rZkalistrrrr<�rMzDR_coeff_new.<locals>.<genexpr>cSrr)�absrArrrr�r z DR_coeff_new.<locals>.<listcomp>rr)rd)r^rfrgrTrr"rr~�	num_edgesrlr|�
flow_solve�cycle_basisr�
mpoly_specialrF)rrr,r2r.r-r/rRr>rQr@r^rs�_�m0�h0rurxrwrv�deg�u�VbasisZspin_factor�mpolyrrrrO�s8*

&rOcs�tt|||d��}|r|dur|�||d�|r#dd�|D�}g}
t��}t|�}|D]��d}tj�fdd�t|�D��D]V�|t��fdd�t|�D����fdd��D��|r{|ritd	d
��D��rz|t���fdd
�t|�D��7}qA|r�tdd
��D��r�|t���fd
d�t|�D��7}qA|r�|
�|d��|�d|
|�q/|
�|t	�|��q/t
||
d�}|��|kr�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|�qSr[r)r�qrrrr�r z!mpoly_special.<locals>.<listcomp>rc�g|]}tt����qSr��listr(rA�rbrrr��c�g|]
}�|�|�qSrrrA�r��coeffrrr��c�g|]}|��qSrr�r�vir�rrr�r cs��|]	}|ddkVqdSrKrrLrrrr<�rMz mpoly_special.<locals>.<genexpr>c3s8�|]}t�|d�|d�|���VqdS)rrN)�econtribrA)rvrbr4rrr<�s�6csr�rKrrLrrrr<�rMcs(g|]}�|��|�|�qSrrrA)rurbr4rrr�rSrrdz0Polynomial has higher degree in r than expected!)
r�r(rqr!�	itertools�productr"�allrrr�degreer#)rur�r�r��start�degrr>rQrwrvr.r@�mrange�mvalues�rankZulen�total�resultr)r�r�rurvrbr4rr��s6  "�"�&r�cs8t||�||f}|��fdd�t||d�D��S)Nc3s>�|]}d|t�t��|d�|d|dVqdSre)rr)rrb�rd�w1rrr<�s�<zecontrib.<locals>.<genexpr>r)�edge_power_seriesr()�e1�e2r�rdZ	polycoeffrr�rr��s$r�cs�ttd|d�}|���t|d|dd�}|��\��t���fdd�t|d�D��}dt|���}dd	�|����D�S)
NrrzX,Yr)�default_precc3s2�|]}�|�|d�|dVqdSr}rrA��A�X�Yrrr<s�0z$edge_power_series.<locals>.<genexpr>cSsi|]	\}}t|�|�qSr)r')rr/�itrrrrDrEz%edge_power_series.<locals>.<dictcomp>)	r
rrCrr"r(r�dict�items)r�r3�Src�hrr�rr�s"r�c
s�tt|||d��}g}t��}|D]=�d}tj�fdd�t|�D��D]%�|t��fdd�t|�D��}	�fdd�|	D�}	||�g|	�R�7}q%|�|�qt||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).
    rrcr�rr�rAr�rrrr�z$mpoly_affine_sum.<locals>.<listcomp>cr�rrrAr�rrrr�cr�rrr�r�rrrr rd)r�r(r!r�r�r"rqr)
�Pr�r�r�r�r�r�r�r�r4r)r�r�rbr�mpoly_affine_sums  r�c
s`|dur
ttd|�}�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��}�dur��fdd��D��|dkr�||�|
t
�fd
d�|��D��7}
qO|
|��||7}
qO|
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
rrA)r.�	gridwidthrrrXs&z,multivariate_interpolate.<locals>.<listcomp>cs,g|]}�|t�dtd����qSr�r�rA)r.�	gridshiftr�rrrZs,cs2g|]�t�����fdd�t�d�D���qS)cs0g|]}|��kr��|����qSrr)r�j)�	generatorr�rB�p�shiftrrr_s�z7multivariate_interpolate.<locals>.<listcomp>.<listcomp>r)rr(�r)r.r�r�r�r�)rBrr_s
�
�cs g|]}��|�|�qSrrrA)r�r�r�rrrbs csi|]	}�|�|�qSrrrA)r��pvalrrrDcrEz,multivariate_interpolate.<locals>.<dictcomp>csg|]}�|��qSrr)r�val)�transf_polyrrrer c3s�|]}|�VqdSr9r)r�e)�multrrr<ms�z+multivariate_interpolate.<locals>.<genexpr>)r
rrCrhr�r(r�r�rrFr)
�fr.r2r�r3r�r�r��cube�pointsr�Zlagr�valuer)	r.r�r�r�r�r�r�r�r�r�multivariate_interpolate(s2#
� r�c
sL�����fdd�}|durttdd�td|d�D��}�dur)|��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�s�|
�|��}n|
�	|��}|r�|�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)r0r1r?r@)rZ)r-)r1r.r,r?r@rrr��szDRpoly.<locals>.fNcSsg|]}d|�qS)za%srrArrrr�r zDRpoly.<locals>.<listcomp>rrrcSsg|]}d�qS)r_rrArrrr�srG)r3r�r�r�cs.i|]}�|td�d�|td��qSr�rrA)rCrrrD�s.zDRpoly.<locals>.<dictcomp>)r3r�)
r
rr(rCrr'r�rFr+r*)r,r.r2Zdplusr0r1�ringrCr=r>r?r@r�r3r�ZshiftvecZR_transfr��interp�ansr)r1r.r,rCr?r@rrVss,E( rVcCsJg}|D]}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�rqr)Zpolyvecr.Z	resultvec�pi�s�crbrrr�
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|�}|dkrt|�dkr��t|�d�S|�kr9t|��dkr9ttd�d��|}��t|�d�S|dkrCt|�dksM|�krQt|��krQ���Sttd�d��|}t|�|gt|��dgt|��dgg�d�dfg�}td|��f��|�S)Nrrr)	�setr!rtr�r(�zerorrri)�l�IZi_setZIcompZgra)r3r,r2rr�delt
s(.�zHain_divisor.<locals>.deltc
s8g|]�t���fdd�tttd�d���D���qS)cs0g|]}t�fdd�|D��d��|��qS)csg|]}�|d�qS�rrrA)r�rrrr�z6Hain_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�r2)r�rrs
��z Hain_divisor.<locals>.<listcomp>r)r_�)r!rr"r(r)r,r�r�r)r�r3r�r,r2r�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>rQr?)rrZ)r,r2r?rdr�r.rGr�rrr�
ThetaClass#s1

Jr�)NNTF)F)rNNNN)	rTFNNFFr8F)r8)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.partitionrr7rZr|rOr�r�r�r�r�rVr�r�r�rrrr�<module>sF
	.
5
8'



Kg-