{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Example 7.6 (Distribution of Leaves in Planar Trees)\n", "We use Sturm's theorem to verify minimality of a critical point in a parametrized direction. \n", "*Requirements: None*" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}\\frac{{\\left(u y z - y z - 2 \\, y + 1\\right)} y}{u y z - u z - y z - y + 1}\n", "\\end{math}" ], "text/plain": [ "(u*y*z - y*z - 2*y + 1)*y/(u*y*z - u*z - y*z - y + 1)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Recall from Example 3.11 in Chapter 3 that the number of binary trees on n nodes with\n", "# k leaves is the coefficient of u^k*y^n*z^n in the power series expansion of the following\n", "var('u,y,z,s,λ,t')\n", "F = (u*y*z - y*z - 2*y + 1)*y/(u*y*z - u*z - y*z - y + 1)\n", "G,H = F.numerator_denominator()\n", "r = [s,1,1]\n", "show(F)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The ideal generated by [a1*a3 - s, a1*s^2 - 2*a1*s + a1 - s^2, a2 - s, a3*s - s^2 + 2*s - 1, b1, b2, b3, lambdaR - s + 1, lambdaI] has (for fixed s) a single solution:\n" ] }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}\\left[a_{1} = \\frac{s^{2}}{s^{2} - 2 \\, s + 1}, a_{2} = s, a_{3} = \\frac{s^{2} - 2 \\, s + 1}{s}, b_{1} = 0, b_{2} = 0, b_{3} = 0, \\mathit{lambdaR} = s - 1, \\mathit{lambdaI} = 0\\right]\n", "\\end{math}" ], "text/plain": [ "[a1 == s^2/(s^2 - 2*s + 1),\n", " a2 == s,\n", " a3 == (s^2 - 2*s + 1)/s,\n", " b1 == 0,\n", " b2 == 0,\n", " b3 == 0,\n", " lambdaR == s - 1,\n", " lambdaI == 0]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# We split the variables into real/imaginary components and define the extended critical point system\n", "var('a1,a2,a3,b1,b2,b3,lambdaR,lambdaI')\n", "assume(a1,'real'); assume(a2,'real'); assume(a3,'real')\n", "assume(b1,'real'); assume(b2,'real'); assume(b3,'real')\n", "Hc = H.subs(u=a1+I*b1, y=a2+I*b2, z=a3+I*b3)\n", "Hr = Hc.real()\n", "Hi = Hc.imag()\n", "CPab1 = [diff(Hr,v)*v + diff(Hr,w)*w - R*lambdaR for (v,w,R) in zip([a1,a2,a3],[b1,b2,b3],r)]\n", "CPab2 = [diff(Hi,v)*v + diff(Hi,w)*w - R*lambdaI for (v,w,R) in zip([a1,a2,a3],[b1,b2,b3],r)]\n", "\n", "# Compute a Gröbner basis for the critical point equations in the a and b variables\n", "R = PolynomialRing(QQ,9,'a1,a2,a3,b1,b2,b3,lambdaR,lambdaI,s',order='lex')\n", "J = R.ideal([R(k) for k in [Hr,Hi] + CPab1 + CPab2])\n", "GB = R.ideal([R(k) for k in [Hr,Hi] + CPab1 + CPab2]).groebner_basis()\n", "\n", "# Note there are a finite number of (complex) solutions! \n", "[cp] = solve([SR(k) for k in GB],[a1,a2,a3,b1,b2,b3,lambdaR,lambdaI])\n", "print(\"The ideal generated by {} has (for fixed s) a single solution:\".format(GB))\n", "show(cp)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# To determine minimality, we add the extra equations using x and y variables\n", "# First, define xj + I*yj as a root of H\n", "# Then encode that the coordinate-wise moduli of xj + I*yj is a multiple of crit pt aj + I*bj\n", "# Finally, add the extra equations derived from critical point method\n", "var('x1,x2,x3,y1,y2,y3,ν')\n", "Hrxy = Hr.subs(a1==x1,a2==x2,a3==x3,b1==y1,b2==y2,b3==y3)\n", "Hixy = Hi.subs(a1==x1,a2==x2,a3==x3,b1==y1,b2==y2,b3==y3)\n", "mod = [X^2+Y^2 - t*(A^2+B^2) for (X,Y,A,B) in zip([x1,x2,x3],[y1,y2,y3],[a1,a2,a3],[b1,b2,b3])]\n", "nuxy = [(Y - ν*X)*diff(Hrxy,X) - (X + ν*Y)*diff(Hrxy,Y) for (X,Y) in zip([x1,x2,x3],[y1,y2,y3])]\n", "\n", "# Define the ideal with all these equations\n", "S = PolynomialRing(QQ,17,'a1,a2,a3,b1,b2,b3,x1,x2,x3,y1,y2,y3,lambdaR,lambdaI,ν,s,t',order='lex')\n", "Jxy = S.ideal([S(k) for k in list(GB) + [Hrxy,Hixy] + mod + nuxy])" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}(t - 1) \\cdot (s^{4} t^{2} - 3 s^{2} t + 2 s t - t + 1) \\cdot (s^{4} t^{3} - s^{4} t^{2} + 4 s^{3} t^{2} - 11 s^{2} t^{2} - s^{2} t + 6 s t^{2} + 6 s t - t^{2} - 2 t - 1) \\cdot (s^{4} t^{3} - s^{4} t^{2} + 4 s^{3} t^{2} - 3 s^{2} t^{2} - s^{2} t + 2 s t^{2} + 2 s t - t^{2} - 2 t - 1) \\cdot (s^{4} t^{3} - s^{4} t^{2} + 8 s^{3} t^{2} - 11 s^{2} t^{2} + 3 s^{2} t + 6 s t^{2} - 6 s t - t^{2} + 2 t - 1)\n", "\\end{math}" ], "text/plain": [ "(t - 1) * (s^4*t^2 - 3*s^2*t + 2*s*t - t + 1) * (s^4*t^3 - s^4*t^2 + 4*s^3*t^2 - 11*s^2*t^2 - s^2*t + 6*s*t^2 + 6*s*t - t^2 - 2*t - 1) * (s^4*t^3 - s^4*t^2 + 4*s^3*t^2 - 3*s^2*t^2 - s^2*t + 2*s*t^2 + 2*s*t - t^2 - 2*t - 1) * (s^4*t^3 - s^4*t^2 + 8*s^3*t^2 - 11*s^2*t^2 + 3*s^2*t + 6*s*t^2 - 6*s*t - t^2 + 2*t - 1)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Compute the corresponding Gröbner basis. This can take a minute or so.\n", "# (Note: the same Gröbner computation is faster in Maple)\n", "GB2 = Jxy.groebner_basis()\n", "\n", "# The values of t at the solutions of the system satisfy the following\n", "tPol = GB2[-1].factor()\n", "show(tPol)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# To prove minimality for any s in (0,1) we must show that this polynomial\n", "# has no root with t in (0,1). We do this using Sturm sequences, examining\n", "# each factor -- other than t-1, which trivially has no root in (0,1) -- \n", "# seperately. Details of Sturm sequences are given in the textbook.\n", "\n", "# Function to compute a Sturm sequence\n", "def Sturm(poly):\n", " ST = []\n", " q = [poly, diff(poly,t)]\n", " while q[-1] != 0:\n", " _,r = q[-2].quo_rem(q[-1])\n", " q += [-r]\n", " return q[:-1]\n", "\n", "# Function to count sign alternations of sequence at a point\n", "def alternations(L,pt):\n", " alt = 0\n", " L2 = [p.subs(s=pt) for p in L if p.subs(s=pt) != 0]\n", " for k in range(len(L2)-1):\n", " if sign(L2[k]*L2[k+1])<0: alt += 1\n", " return alt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### First Factor" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This factor is s^4*t^2 + (-3*s^2 + 2*s - 1)*t + 1\n" ] }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}\\verb|Sturm|\\phantom{\\verb!x!}\\verb|sequence|\\phantom{\\verb!x!}\\verb|at|\\phantom{\\verb!x!}\\verb|t=0|\\phantom{\\verb!x!}\\verb|is| \\left[1, -3 s^{2} + 2 s - 1, \\frac{\\frac{5}{4} s^{4} - 3 s^{3} + \\frac{5}{2} s^{2} - s + \\frac{1}{4}}{s^{4}}\\right]\n", "\\end{math}" ], "text/plain": [ "'Sturm sequence at t=0 is' [1, -3*s^2 + 2*s - 1, (5/4*s^4 - 3*s^3 + 5/2*s^2 - s + 1/4)/s^4]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}\\verb|Sturm|\\phantom{\\verb!x!}\\verb|sequence|\\phantom{\\verb!x!}\\verb|at|\\phantom{\\verb!x!}\\verb|t=1|\\phantom{\\verb!x!}\\verb|is| \\left[s^{4} - 3 s^{2} + 2 s, 2 s^{4} - 3 s^{2} + 2 s - 1, \\frac{\\frac{5}{4} s^{4} - 3 s^{3} + \\frac{5}{2} s^{2} - s + \\frac{1}{4}}{s^{4}}\\right]\n", "\\end{math}" ], "text/plain": [ "'Sturm sequence at t=1 is' [s^4 - 3*s^2 + 2*s,\n", " 2*s^4 - 3*s^2 + 2*s - 1,\n", " (5/4*s^4 - 3*s^3 + 5/2*s^2 - s + 1/4)/s^4]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# First factor \n", "p1 = QQ[s].fraction_field()[t](tPol)\n", "q = Sturm(p1)\n", "C0 = [k.subs(t=0) for k in q]\n", "C1 = [k.subs(t=1) for k in q]\n", "print(\"This factor is\",p1)\n", "show(\"Sturm sequence at t=0 is\", C0)\n", "show(\"Sturm sequence at t=1 is\", C1)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# No roots of a numerator or denominator for either Sturm sequence lie in (0,1)\n", "rts = flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C1])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C1])\n", "rts01 = list(filter(lambda x: x>0 and x<1, rts))\n", "rts01" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Thus, the signs are the same for all s in (0,1), including both endpoints \n", "# This means the number of roots of this factor with t in (0,1] for s in (0,1) is\n", "alternations(C1,1/2) - alternations(C0,1/2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Second Factor" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This factor is s^4*t^3 + (-s^4 + 4*s^3 - 11*s^2 + 6*s - 1)*t^2 + (-s^2 + 6*s - 2)*t - 1\n" ] } ], "source": [ "p2 = QQ[s].fraction_field()[t](tPol)\n", "q = Sturm(p2)\n", "C0 = [k.subs(t=0) for k in q]\n", "C1 = [k.subs(t=1) for k in q]\n", "print(\"This factor is\",p2)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.3542486889354094?, 0.3851648071345041?, 0.3941724074329110?]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The sign conditions of the Sturm sequence can only change at roots of the numerator\n", "# or denominator of its entries -- i.e., for s in (0,1) it can only change at these values\n", "rts = flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C1])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C1])\n", "rts01 = list(filter(lambda x: x>0 and x<1, rts))\n", "rts01 = sorted(set(rts01))\n", "rts01" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 0, 0, 0]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# For s in (0,1) between these points the sign conditions are constant,\n", "# so we can test the sign conditions by picking values of s between each point\n", "# This shows there are no roots for t in (0,1) and s in (0,1) when s not in rts01\n", "pts = [0.1, 0.36, 0.39, 0.5]\n", "[alternations(C1,pt) - alternations(C0,pt) for pt in pts]" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[7.140984766613703?], [5.388399446915442?], [5.018578328500075?]]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Manually show there are no roots for t in (0,1) when s in rts01 by solving the poly\n", "[AA[t](SR(p2).subs(s=rt)).roots(multiplicities=False) for rt in rts01]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Third Factor" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This factor is s^4*t^3 + (-s^4 + 4*s^3 - 3*s^2 + 2*s - 1)*t^2 + (-s^2 + 2*s - 2)*t - 1\n" ] } ], "source": [ "p3 = QQ[s].fraction_field()[t](tPol)\n", "q = Sturm(p3)\n", "C0 = [k.subs(t=0) for k in q]\n", "C1 = [k.subs(t=1) for k in q]\n", "print(\"This factor is\",p3)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.7254470427491280?]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Find roots in (0,1)\n", "rts = flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C1])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C1])\n", "rts01 = list(filter(lambda x: x>0 and x<1, rts))\n", "rts01 = sorted(set(rts01))\n", "rts01" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 0]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# For s in (0,1) on each side of this point the sign conditions are constant,\n", "# so we can test the sign conditions by picking two values of s in (0,1)\n", "# This shows there are no roots for t in (0,1) and s in (0,1) when s not the element of rts01\n", "pts = [0.1,0.9]\n", "[alternations(C1,pt) - alternations(C0,pt) for pt in pts]" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[2.148303747649492?]]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Manually show there are no roots for t in (0,1) when s in rts01 by solving the poly\n", "[AA[t](SR(p3).subs(s=rt)).roots(multiplicities=False) for rt in rts01]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Fourth (Final) Factor" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This factor is s^4*t^3 + (-s^4 + 8*s^3 - 11*s^2 + 6*s - 1)*t^2 + (3*s^2 - 6*s + 2)*t - 1\n" ] } ], "source": [ "# Final factor \n", "p4 = QQ[s].fraction_field()[t](tPol)\n", "q = Sturm(p4)\n", "C0 = [k.subs(t=0) for k in q]\n", "C1 = [k.subs(t=1) for k in q]\n", "print(\"This factor is\",p4)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.2370545200314687?,\n", " 0.2403702750125248?,\n", " 0.2548844570965663?,\n", " 0.2616705580491203?,\n", " 0.3720842206893895?,\n", " 0.4226497308103743?]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Find roots in (0,1)\n", "rts = flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C0])\n", "rts += flatten([QQ[s](SR(k).numerator()).roots(AA, multiplicities=False) for k in C1])\n", "rts += flatten([QQ[s](SR(k).denominator()).roots(AA, multiplicities=False) for k in C1])\n", "rts01 = list(filter(lambda x: x>0 and x<1, rts))\n", "rts01 = sorted(set(rts01))\n", "rts01" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 0, 0, 0, 0, 0, 0]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# For s in (0,1) on each side of this point the sign conditions are constant,\n", "# so we can test the sign conditions by picking two values of s in (0,1)\n", "# This shows there are no roots for t in (0,1) and s in (0,1) when s not the element of rts01\n", "pts = [0.1, 0.24, 0.25, 0.26, 0.3, 0.4, 0.9]\n", "[alternations(C1,pt) - alternations(C0,pt) for pt in pts]" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[1.6630008475?, 13.799307214583437?],\n", " [1.6745190182?],\n", " [1.725018869517811?],\n", " [1.748599118643231?],\n", " [2.084201751623?],\n", " [2.170435189413383?]]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Manually show there are no roots for t in (0,1) when s in rts01 by solving the poly\n", "[AA[t](SR(p4).subs(s=rt)).roots(multiplicities=False) for rt in rts01]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Computing Asymptotics\n", "\n", "Combining everything above, we have shown that the single critical point is minimal for all $s \\in (0,1)$. We end by computing asymptotics after importing our code for smooth ACSV from Chapter 5. If you just want to compute asymptotics *assuming* minimality, you only need to run the code in this section." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# Import code for smooth asymptotics\n", "# Set a parameter to help simplify some algebraic numbers\n", "maxima_calculus('algebraic: true;')\n", "\n", "# Procedure to get Hessian appearing in asymptotics\n", "# Input: H, member of the symbolic ring\n", "# r, direction vector (which can contain symbolic entries)\n", "# vars, vector of variables\n", "# CP, a dictionary mapping elements of vars\n", "# Output: The Hessian H defined in Lemma 5.5 of the textbook at the point w defined by CP\n", "def getHes(H,r,vars,CP):\n", " dd = len(vars)\n", " V = zero_vector(SR,dd)\n", " U = matrix(SR,dd)\n", " M = matrix(SR,dd-1)\n", "\n", " for j in range(dd):\n", " V[j] = r[j]/r[-1]\n", " for i in range(dd):\n", " U[i,j] = vars[i]*vars[j]*diff(H,vars[i],vars[j])/vars[-1]/diff(H,vars[-1])\n", " for i in range(dd-1):\n", " for j in range(dd-1):\n", " M[i,j] = V[i]*V[j] + U[i,j] - V[j]*U[i,-1] - V[i]*U[j,-1] + V[i]*V[j]*U[-1,-1]\n", " if i == j: M[i,j] = M[i,j] + V[i]\n", " return M(CP)\n", "\n", "# Procedure to apply differential operator to f and set all variables to zero\n", "# Input: dop, element of a DifferentialWeylAlgebra over a polynomial ring\n", "# f, an element of the base polynomial ring of dop\n", "# Output: dop(f) evaluated when all variables are zero\n", "def eval_op(dop, f):\n", " if len(f.parent().gens()) == 1:\n", " return add([prod([factorial(k) for k in E])*E*f[E] for E in dop])\n", " else:\n", " return add([prod([factorial(k) for k in E])*E*f[(v for v in E)] for E in dop])\n", "\n", "# Procedure to get critical points of rational function with denominator H, in direction r\n", "# Input: H, member of the symbolic ring\n", "# r, direction vector (which can contain symbolic entries)\n", "# vars, vector of variables\n", "# Output: Solutions (if found by solve) of the smooth critical point equations of H in the direction r\n", "def critpt(H,r,vars):\n", " d = len(vars)\n", " criteqs = [H] + [r[j]*vars*diff(H,vars) - r*vars[j]*diff(H,vars[j]) for j in range(1,d)]\n", " return solve(criteqs,vars,solution_dict=true)\n", "\n", "# Procedure to compute asymptotic contribution of a strictly minimal contributing point\n", "# Input: G, member of the symbolic ring\n", "# H, member of the symbolic ring\n", "# r, direction vector (which can contain symbolic entries)\n", "# vars, vector of variables\n", "# CP, a dictionary mapping elements of vars to coordinates of a strictly minimal contributing point\n", "# M, positive integer describing the number of terms in the asymptotic expansion to compute\n", "# g, parametrization of variable vars[-1] near CP, in terms of the remaining variables\n", "# Output: ex, pw, se such that ex*pw*(se+O(n^(M-1)) gives an asymptotic expansion of the r-diagonal of \n", "# G/H in the variables vars, to order M.\n", "# NOTE: Unlike the textbook, M here refers to the number of terms in the expansion\n", "# (not the order of the expansion, so M should be at least 1)\n", "def smoothContrib(G,H,r,vars,CP,M,g):\n", " # Preliminary definitions\n", " dd = len(vars)\n", " field = SR\n", " tvars = list(var('t%d'%i) for i in range(dd-1))\n", " dvars = list(var('dt%d'%i) for i in range(dd-1))\n", "\n", " # Define differential Weyl algebra and set variable names\n", " W = DifferentialWeylAlgebra(PolynomialRing(field,tvars))\n", " WR = W.base_ring()\n", " T = PolynomialRing(field,tvars).gens()\n", " D = list(W.differentials())\n", "\n", " # Compute Hessian matrix and differential operator Epsilon\n", " HES = getHes(H,r,vars,CP)\n", " HESinv = HES.inverse()\n", " v = matrix(W,[D[k] for k in range(dd-1)])\n", " Epsilon = -(v * HESinv.change_ring(W) * v.transpose())[0,0]\n", "\n", " # Define quantities for calculating asymptotics\n", " tsubs = [v == v.subs(CP)*exp(I*t) for [v,t] in zip(vars,tvars)]\n", " tsubs += [vars[-1]==g.subs(tsubs)]\n", " P = (-G/g/diff(H,vars[-1])).subs(tsubs)\n", " psi = log(g.subs(tsubs)/g.subs(CP)) + I * add([r[k]*tvars[k] for k in range(dd-1)])/r[-1]\n", " v = matrix(SR,[tvars[k] for k in range(dd-1)])\n", " psiTilde = psi - (v * HES * v.transpose())[0,0]/2\n", "\n", " # Recursive function to convert symbolic expression to polynomial in t variables\n", " def to_poly(p,k):\n", " if k == 0:\n", " return add([a*T[k]^int(b) for [a,b] in p.coefficients(tvars[k])])\n", " return add([to_poly(a,k-1)*T[k]^int(b) for [a,b] in p.coefficients(tvars[k])])\n", "\n", " # Compute Taylor expansions to sufficient orders\n", " N = 2*M\n", " PsiSeries = to_poly(taylor(psiTilde,*((v,0) for v in tvars), N),dd-2)\n", " PSeries = to_poly(taylor(P,*((v,0) for v in tvars), N),dd-2)\n", "\n", " # Precompute products used for asymptotics\n", " EE = [Epsilon^k for k in range(3*M-2)]\n", " PP = [PSeries] + [0 for k in range(2*M-2)]\n", " for k in range(1,2*M-1):\n", " PP[k] = PP[k-1]*PsiSeries\n", " \n", " # Function to compute constants appearing in asymptotic expansion\n", " def Clj(l,j):\n", " return (-1)^j*SR(eval_op(EE[l+j],PP[l]))/(2^(l+j)*factorial(l)*factorial(l+j))\n", " \n", " # Compute different parts of asymptotic expansion\n", " var('n')\n", " ex = (prod([1/v^k for (v,k) in zip(vars,r)]).subs(CP).canonicalize_radical())^n\n", " pw = (r[-1]*n)^((1-dd)/2)\n", " se = sqrt((2*pi)^(1-dd)/HES.det()) * add([add([Clj(l,j) for l in range(2*j+1)])/(r[-1]*n)^j for j in range(M)])\n", " \n", " return ex, pw, se.canonicalize_radical()\n", "\n", "# Procedure to aid in printing an asymptotic expansion\n", "# Procedure to get critical points of rational function with denominator H, in direction r\n", "# Input: ex,pw,se as returned by smoothContrib(G,H,r,vars,CP,M,g)\n", "# Output: None (function pretty prints the asymptotic expression defined by ex,pw,se, and M)\n", "def disp_asm(ex,pw,se,M):\n", " show(ex*pw,LatexExpr(\"\\\\Bigg(\"), se, LatexExpr(\"+ O\\\\Bigg(\"), n^(-M), LatexExpr(\"\\\\Bigg)\\\\Bigg)\"))" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}\\frac{{\\left(u y z - y z - 2 \\, y + 1\\right)} y}{u y z - u z - y z - y + 1}\n", "\\end{math}" ], "text/plain": [ "(u*y*z - y*z - 2*y + 1)*y/(u*y*z - u*z - y*z - y + 1)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Restate basic parameters to make this section independent of above\n", "var('u,y,z,s')\n", "F = (u*y*z - y*z - 2*y + 1)*y/(u*y*z - u*z - y*z - y + 1)\n", "show(F)\n", "G,H = F.numerator_denominator()\n", "r = [s,1,1]\n", "vars = [u,y,z]" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The asymptotic expansion for the [s,1,1] diagonal begins\n" ] }, { "data": { "text/html": [ "" ], "text/latex": [ "\\begin{math}\n", "\\newcommand{\\Bold}{\\mathbf{#1}}\\frac{\\left(\\frac{{\\left(s - 1\\right)}^{2 \\, s}}{{\\left(s^{2} - 2 \\, s + 1\\right)} s^{2 \\, s}}\\right)^{n}}{n} \\Bigg( \\frac{1}{2 \\, \\pi n} + O\\Bigg( \\frac{1}{n^{2}} \\Bigg)\\Bigg)\n", "\\end{math}" ], "text/plain": [ "((s - 1)^(2*s)/((s^2 - 2*s + 1)*s^(2*s)))^n/n \\Bigg( 1/2/(pi*n) + O\\Bigg( n^(-2) \\Bigg)\\Bigg)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Get critical point (shown minimal above)\n", "[CP] = critpt(H,r,vars)\n", "\n", "# Get and print asymptotics\n", "M = 2\n", "g = vars[-1].subs(solve(H,vars[-1]))\n", "ex,pw,se = smoothContrib(G,H,r,vars,CP,M,g)\n", "print(\"The asymptotic expansion for the [s,1,1] diagonal begins\")\n", "disp_asm(ex,pw,se,M)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.2", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 2 }