Skip to content

Commit 76aadbb

Browse files
Andrew LuoAndrew Luo
authored andcommitted
Add function to compute asymptotic around point (preliminary)
1 parent eb199f7 commit 76aadbb

File tree

2 files changed

+176
-72
lines changed

2 files changed

+176
-72
lines changed

sage_acsv/asymptotics.py

Lines changed: 172 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
from sage.algebras.weyl_algebra import DifferentialWeylAlgebra
120120
from sage.arith.misc import gcd
121121
from sage.arith.srange import srange
122+
from sage.combinat.combination import Combinations
122123
from sage.functions.log import log, exp
123124
from sage.functions.other import factorial
124125
from sage.matrix.constructor import matrix
@@ -662,19 +663,8 @@ def diagonal_asymptotics_combinatorial(
662663
H = R(SR(H))
663664
vs = [R(SR(v)) for v in vs]
664665
subs_dict = {vs[i]: cp[i] for i in range(d)}
665-
poly_factors = H.factor()
666-
unit = poly_factors.unit()
667-
factors = []
668-
multiplicities = []
669-
for factor, multiplicity in poly_factors:
670-
const = factor.coefficients()[-1]
671-
unit *= const**multiplicity
672-
factor /= const
673-
if factor.subs(subs_dict) != 0:
674-
unit *= factor.subs(subs_dict)
675-
continue
676-
factors.append(factor)
677-
multiplicities.append(multiplicity)
666+
667+
unit, factors, multiplicities = _get_factorization(H, subs_dict)
678668
s = len(factors)
679669
normals = matrix(
680670
[[f.derivative(v).subs(subs_dict) for v in vs] for f in factors]
@@ -706,67 +696,12 @@ def diagonal_asymptotics_combinatorial(
706696
else:
707697
raise ACSVException("Cannot find parametrizing set.")
708698

709-
# Step 3: Compute the gamma matrix as defined in 9.10
710-
Gamma = matrix(
711-
[[(v * Q.derivative(v)).subs(subs_dict) for v in vs] for Q in factors]
712-
+ [
713-
[v.subs(subs_dict) if vs.index(v) == i else 0 for i in range(d)]
714-
for v in vs[: d - s]
715-
]
716-
)
717-
718-
# Some constants appearing for higher order singularities
719-
mult_fac = prod([factorial(m - 1) for m in multiplicities])
720-
r_gamma_inv = prod(
721-
x ** (multiplicities[i] - 1)
722-
for i, x in enumerate(list(vector(r) * Gamma.inverse())[:s])
723-
)
724-
# If cp lies on a single smooth component, we can compute asymptotics
725-
# like in the smooth case
726-
if s == 1 and sum(multiplicities) == 1:
727-
n = SR.var("n")
728-
expansion = sum(
729-
term / (r[-1] * n) ** (term_order)
730-
for term_order, term in enumerate(
731-
_general_term_asymptotics(G, H, r, vs, cp, expansion_precision)
732-
)
699+
asm_quantities.append(
700+
_compute_asm_quantity(
701+
G, H, vs, cp, r, subs_dict, unit ,factors, multiplicities, expansion_precision
733702
)
734-
Det = compute_hessian(H, vs, r).determinant()
735-
B = SR(1 / Det.subs(subs_dict) / r[-1] ** (d - 1) / 2 ** (d - 1))
736-
else:
737-
# Higher order expansions not currently supported for non-smooth critical points
738-
if expansion_precision > 1:
739-
acsv_logger.warning(
740-
"Higher order expansions are not supported in the non-smooth case. Defaulting to expansion_precision 1."
741-
)
742-
# For non-complete intersections, we must compute the parametrized Hessian matrix
743-
if s != d:
744-
Qw = compute_implicit_hessian(factors, vs, r, subs=subs_dict)
745-
expansion = SR(abs(prod([v for v in vs[: d - s]]).subs(subs_dict)) * G.subs(subs_dict) / abs(Gamma.determinant()) / unit)
746-
B = SR(
747-
1
748-
/ Qw.determinant()
749-
/ 2 ** (d - s)
750-
)
751-
else:
752-
expansion = SR(G.subs(subs_dict) / unit / abs(Gamma.determinant()))
753-
B = 1
754-
755-
expansion *= (
756-
(-1) ** sum([m - 1 for m in multiplicities]) * r_gamma_inv / mult_fac
757703
)
758704

759-
T = prod(SR(vs[i].subs(subs_dict)) ** r[i] for i in range(d))
760-
C = SR(1 / T)
761-
D = QQ((s - d) / 2 + sum(multiplicities) - s)
762-
try:
763-
B = QQbar(B)
764-
C = QQbar(C)
765-
except (ValueError, TypeError):
766-
pass
767-
768-
asm_quantities.append([expansion, B, C, D, s])
769-
770705
asm_vals = [(c, d, b.sqrt(), a, s) for a, b, c, d, s in asm_quantities]
771706

772707
if as_symbolic:
@@ -813,7 +748,156 @@ def diagonal_asymptotics_combinatorial(
813748

814749
return result
815750

751+
def compute_asymptotic_contribution(
752+
F,
753+
critical_point,
754+
r=None
755+
):
756+
G, H, variable_map = _prepare_symbolic_fraction(F)
757+
vs = list(variable_map.values())
816758

759+
if r is None:
760+
n = len(H.variables())
761+
r = [1 for _ in range(n)]
762+
763+
cp = critical_point
764+
765+
d = len(vs)
766+
767+
# Make sure G and H are coprime, and that H does not vanish at 0
768+
G, H = rational_function_reduce(G, H)
769+
if H.subs({v: 0 for v in H.variables()}) == 0:
770+
raise ValueError("Denominator vanishes at 0.")
771+
772+
# Step 1: Determine if pt is a transverse multiple point of H,
773+
# and compute the factorization
774+
subs_dict = {vs[i]: cp[i] for i in range(d)}
775+
776+
# Factorization works weirdly in symbolic ring
777+
R = PolynomialRing(QQbar, len(vs), vs)
778+
unit, all_factors, all_multiplicities = _get_factorization(R(H))
779+
unit, all_factors, all_multiplicities = SR(unit), [SR(f) for f in all_factors], [SR(f) for f in all_multiplicities]
780+
781+
asymptotics = []
782+
783+
# Since critical point might be symbolic, we need to consider all flats it may lie on
784+
for factor_multiplicities in Combinations(zip(all_factors, all_multiplicities)):
785+
if not factor_multiplicities:
786+
continue
787+
factors, multiplicities = zip(*factor_multiplicities)
788+
# Determine whether it's possible for the critical point vanish in this
789+
# combination of factors
790+
if any([f.subs(subs_dict) != 0 for f in factors]):
791+
# TODO - check if some parameters allow this to hold in certain conditions
792+
continue
793+
794+
s = len(factors)
795+
normals = matrix(
796+
[[f.derivative(v).subs(subs_dict) for v in vs] for f in factors]
797+
)
798+
if normals.rank() < s:
799+
raise ACSVException(
800+
"Not a transverse intersection. Cannot deal with this case."
801+
)
802+
803+
# Step 2: Find the locally parametrizing coordinates of the point pt
804+
# Since we have d variables and s factors, there should be d-s of these
805+
# parametrizing coordinates
806+
# We will try to parametrize with the first d-s coordinates, shuffling
807+
# the vs and r if it doesn't work
808+
for _ in range(s**2):
809+
Jac = matrix(
810+
[
811+
[(v * Q.derivative(v)).subs(subs_dict) for v in vs[d - s :]]
812+
for Q in factors
813+
]
814+
)
815+
if Jac.determinant() != 0:
816+
break
817+
818+
acsv_logger.info("Variables do not parametrize, shuffling")
819+
vs_r_cp = list(zip(vs, r, cp))
820+
shuffle(vs_r_cp) # shuffle mutates the list
821+
vs, r, cp = zip(*vs_r_cp)
822+
else:
823+
raise ACSVException("Cannot find parametrizing set.")
824+
825+
expansion, constant_squared, base, exponent, s = _compute_asm_quantity(
826+
G, H, vs, cp, r, subs_dict, unit ,factors, multiplicities, 1
827+
)
828+
constant = constant_squared.sqrt()
829+
830+
n = SR.var("n")
831+
asymptotics.append(base**n * n**exponent * (pi ** (s - d)).sqrt() * constant * expansion)
832+
833+
# TODO: If input parameters are rational, do some extra checking of validity
834+
835+
return asymptotics
836+
837+
def _compute_asm_quantity(G, H, vs, cp, r, subs_dict, unit, factors, multiplicities, expansion_precision):
838+
s = len(factors)
839+
d = len(vs)
840+
# Step 3: Compute the gamma matrix as defined in 9.10
841+
Gamma = matrix(
842+
[[(v * Q.derivative(v)).subs(subs_dict) for v in vs] for Q in factors]
843+
+ [
844+
[v.subs(subs_dict) if vs.index(v) == i else 0 for i in range(d)]
845+
for v in vs[: d - s]
846+
]
847+
)
848+
849+
# Some constants appearing for higher order singularities
850+
mult_fac = prod([factorial(m - 1) for m in multiplicities])
851+
r_gamma_inv = prod(
852+
x ** (multiplicities[i] - 1)
853+
for i, x in enumerate(list(vector(r) * Gamma.inverse())[:s])
854+
)
855+
# If cp lies on a single smooth component, we can compute asymptotics
856+
# like in the smooth case
857+
if s == 1 and sum(multiplicities) == 1:
858+
n = SR.var("n")
859+
expansion = sum(
860+
term / (r[-1] * n) ** (term_order)
861+
for term_order, term in enumerate(
862+
_general_term_asymptotics(G, H, r, vs, cp, expansion_precision)
863+
)
864+
)
865+
Det = compute_hessian(H, vs, r).determinant()
866+
B = SR(1 / Det.subs(subs_dict) / r[-1] ** (d - 1) / 2 ** (d - 1))
867+
else:
868+
# Higher order expansions not currently supported for non-smooth critical points
869+
if expansion_precision > 1:
870+
acsv_logger.warning(
871+
"Higher order expansions are not supported in the non-smooth case. Defaulting to expansion_precision 1."
872+
)
873+
# For non-complete intersections, we must compute the parametrized Hessian matrix
874+
if s != d:
875+
Qw = compute_implicit_hessian(factors, vs, r, subs=subs_dict)
876+
expansion = SR(abs(prod([v for v in vs[: d - s]]).subs(subs_dict)) * G.subs(subs_dict) / abs(Gamma.determinant()) / unit)
877+
B = SR(
878+
1
879+
/ Qw.determinant()
880+
/ 2 ** (d - s)
881+
)
882+
else:
883+
expansion = SR(G.subs(subs_dict) / unit / abs(Gamma.determinant()))
884+
B = 1
885+
886+
expansion *= (
887+
(-1) ** sum([m - 1 for m in multiplicities]) * r_gamma_inv / mult_fac
888+
)
889+
890+
T = prod(SR(vs[i].subs(subs_dict)) ** r[i] for i in range(d))
891+
C = SR(1 / T)
892+
D = QQ((s - d) / 2 + sum(multiplicities) - s)
893+
try:
894+
B = QQbar(B)
895+
C = QQbar(C)
896+
except (ValueError, TypeError, NotImplementedError):
897+
pass
898+
899+
return [expansion, B, C, D, s]
900+
817901
def _general_term_asymptotics(G, H, r, vs, cp, expansion_precision):
818902
r"""
819903
Compute coefficients of general (not necessarily leading) terms of
@@ -1734,3 +1818,20 @@ def _prepare_expanded_polynomial_ring(variables, direction=None, include_t=True)
17341818
replaced_direction,
17351819
direction_variable_values,
17361820
)
1821+
1822+
def _get_factorization(H, subs_dict=None):
1823+
unit = 1
1824+
poly_factors = H.factor()
1825+
unit = poly_factors.unit()
1826+
factors = []
1827+
multiplicities = []
1828+
for factor, multiplicity in poly_factors:
1829+
const = factor.coefficients()[-1]
1830+
unit *= const**multiplicity
1831+
factor /= const
1832+
if subs_dict is not None and factor.subs(subs_dict) != 0:
1833+
unit *= factor.subs(subs_dict)
1834+
continue
1835+
factors.append(factor)
1836+
multiplicities.append(multiplicity)
1837+
return unit, factors, multiplicities

sage_acsv/helpers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,10 @@ def compute_hessian(H, variables, r, critical_point=None):
165165
try:
166166
V = [QQ(r[k] / r[-1]) for k in range(d)]
167167
except (ValueError, TypeError):
168-
V = [AA(r[k] / r[-1]) for k in range(d)]
168+
try:
169+
V = [AA(r[k] / r[-1]) for k in range(d)]
170+
except (NotImplementedError):
171+
V = [r[k] / r[-1] for k in range(d)]
169172

170173
# Build (d-1) x (d-1) Matrix for Hessian
171174
hessian = [

0 commit comments

Comments
 (0)