Skip to content

Commit 4bceb9c

Browse files
Andrew LuoAndrew Luo
authored andcommitted
Make restrictions more robust
1 parent 76aadbb commit 4bceb9c

File tree

2 files changed

+114
-9
lines changed

2 files changed

+114
-9
lines changed

sage_acsv/asymptotics.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,18 @@
129129
from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing
130130
from sage.rings.ideal import Ideal
131131
from sage.rings.imaginary_unit import I
132+
from sage.rings.fraction_field import FractionField
132133
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
133134
from sage.rings.qqbar import AA, QQbar
134135
from sage.rings.rational_field import QQ
136+
from sage.schemes.affine.affine_space import AffineSpace
135137
from sage.symbolic.constants import pi
136138
from sage.symbolic.ring import SR
137139

138140
from sage_acsv.kronecker import _kronecker_representation
139141
from sage_acsv.helpers import (
140142
ACSVException,
143+
Restriction,
141144
is_contributing,
142145
compute_newton_series,
143146
rational_function_reduce,
@@ -148,7 +151,7 @@
148151
from sage_acsv.debug import Timer, acsv_logger
149152
from sage_acsv.settings import ACSVSettings
150153
from sage_acsv.whitney import whitney_stratification
151-
from sage_acsv.groebner import compute_primary_decomposition, compute_saturation
154+
from sage_acsv.groebner import compute_primary_decomposition, compute_saturation, compute_radical
152155

153156

154157
# we need to monkeypatch a function from the asymptotics module such that creating
@@ -778,18 +781,28 @@ def compute_asymptotic_contribution(
778781
unit, all_factors, all_multiplicities = _get_factorization(R(H))
779782
unit, all_factors, all_multiplicities = SR(unit), [SR(f) for f in all_factors], [SR(f) for f in all_multiplicities]
780783

784+
fvs = list(set([v for ri in r for v in SR(ri).variables()] + [v for cpi in cp for v in SR(cpi).variables()]))
785+
Rf = PolynomialRing(QQ, len(fvs), fvs)
786+
781787
asymptotics = []
788+
restrictions = []
782789

783790
# 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:
791+
for combo in Combinations(list(range(len(all_factors)))):
792+
if not combo:
786793
continue
787-
factors, multiplicities = zip(*factor_multiplicities)
794+
factors = [all_factors[i] for i in combo]
795+
multiplicities = [all_multiplicities[i] for i in combo]
796+
797+
valid_set = Restriction(Rf)
798+
valid_set.setminus(
799+
[all_factors[j] for j in range(len(all_factors)) if j not in combo]
800+
)
801+
788802
# Determine whether it's possible for the critical point vanish in this
789803
# combination of factors
790804
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
805+
valid_set.intersection([f.subs(subs_dict) for f in factors])
793806

794807
s = len(factors)
795808
normals = matrix(
@@ -799,6 +812,12 @@ def compute_asymptotic_contribution(
799812
raise ACSVException(
800813
"Not a transverse intersection. Cannot deal with this case."
801814
)
815+
else:
816+
try:
817+
Id_minors = [Rf(f) for f in normals.minors(s)]
818+
valid_set.setminus(Id_minors)
819+
except:
820+
valid_set = None
802821

803822
# Step 2: Find the locally parametrizing coordinates of the point pt
804823
# Since we have d variables and s factors, there should be d-s of these
@@ -815,6 +834,11 @@ def compute_asymptotic_contribution(
815834
if Jac.determinant() != 0:
816835
break
817836

837+
try:
838+
valid_set = valid_set.setminus([Jac.determinant()])
839+
except:
840+
valid_set = None
841+
818842
acsv_logger.info("Variables do not parametrize, shuffling")
819843
vs_r_cp = list(zip(vs, r, cp))
820844
shuffle(vs_r_cp) # shuffle mutates the list
@@ -823,16 +847,17 @@ def compute_asymptotic_contribution(
823847
raise ACSVException("Cannot find parametrizing set.")
824848

825849
expansion, constant_squared, base, exponent, s = _compute_asm_quantity(
826-
G, H, vs, cp, r, subs_dict, unit ,factors, multiplicities, 1
850+
G, H, vs, cp, r, subs_dict, unit,factors, multiplicities, 1
827851
)
828852
constant = constant_squared.sqrt()
829853

830854
n = SR.var("n")
831855
asymptotics.append(base**n * n**exponent * (pi ** (s - d)).sqrt() * constant * expansion)
856+
restrictions.append(valid_set)
832857

833858
# TODO: If input parameters are rational, do some extra checking of validity
834859

835-
return asymptotics
860+
return restrictions, asymptotics
836861

837862
def _compute_asm_quantity(G, H, vs, cp, r, subs_dict, unit, factors, multiplicities, expansion_precision):
838863
s = len(factors)

sage_acsv/helpers.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@
1919
MonomialGrowthGroup,
2020
)
2121
from sage.rings.ideal import Ideal
22+
from sage.rings.fraction_field import FractionField
23+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
2224
from sage.rings.qqbar import AA, AlgebraicNumber, QQbar
2325
from sage.rings.rational_field import QQ
26+
from sage.schemes.affine.affine_space import AffineSpace
2427
from sage.symbolic.expression import Expression
2528
from sage.symbolic.ring import SymbolicRing, SR
2629
from sage.symbolic.operators import add_vararg
2730
from sage.symbolic.constants import pi
31+
from sage_acsv.groebner import compute_radical, compute_saturation
2832

2933

3034
@dataclass
@@ -57,7 +61,6 @@ class Term:
5761
def __lt__(self, other):
5862
return (self.base, self.power) < (other.base, other.power)
5963

60-
6164
def collapse_zero_part(algebraic_number: AlgebraicNumber) -> AlgebraicNumber:
6265
if algebraic_number.real().is_zero():
6366
algebraic_number = QQbar(algebraic_number.imag()) * QQbar(-1).sqrt()
@@ -567,6 +570,83 @@ def get_expansion_terms(
567570

568571
return decomposed_terms
569572

573+
class Restriction():
574+
def __init__(self, base_ring):
575+
if len(base_ring.gens()) == 0:
576+
self.base_ring = SR
577+
self.base_field = SR
578+
self.inclusion = []
579+
self.exclusion = []
580+
return
581+
582+
self.base_ring = base_ring
583+
self.base_field = FractionField(base_ring)
584+
self.inclusion = Ideal(base_ring.zero())
585+
self.exclusion = Ideal(base_ring.one())
586+
587+
def intersection(self, eqns):
588+
if self.base_ring != SR:
589+
try:
590+
eqns = [self.base_field(f) for f in eqns]
591+
denoms = [f.denominator() for f in eqns]
592+
Id = compute_radical(Ideal([self.base_ring.zero()] + [self.base_ring(f * prod(denoms)) for f in eqns]))
593+
self.inclusion += Id
594+
except:
595+
self.inclusion = eqns + [SR(f) for f in self.inclusion.gens()]
596+
self.exclusion = [SR(f) for f in self.exclusion.gens()]
597+
self.base_ring = SR
598+
self.base_field = SR
599+
else:
600+
self.inclusion += eqns
601+
602+
return self
603+
604+
def setminus(self, eqns):
605+
if self.base_ring != SR:
606+
try:
607+
eqns = [self.base_field(f) for f in eqns]
608+
denoms = [f.denominator() for f in eqns]
609+
Id = compute_radical(Ideal([self.base_ring.zero()] + [self.base_ring(f * prod(denoms)) for f in eqns]))
610+
self.exclusion = self.exclusion.intersection(Id)
611+
except:
612+
self.inclusion = [SR(f) for f in self.inclusion.gens()]
613+
self.exclusion = eqns + [SR(f) for f in self.exclusion.gens()]
614+
self.base_ring = SR
615+
self.base_field = SR
616+
else:
617+
self.exclusion += eqns
618+
619+
return self
620+
621+
def simplify(self):
622+
if self.base_ring == SR:
623+
return
624+
self.inclusion = compute_saturation(self.inclusion, self.exclusion)
625+
self.inclusion = compute_radical(self.inclusion)
626+
self.exclusion = compute_radical(self.exclusion)
627+
628+
def contains(self, other : Restriction):
629+
if self.base_ring == SR:
630+
return False
631+
632+
self.simplify()
633+
other.simplify()
634+
for f in self.inclusion.gens():
635+
if f not in other.inclusion:
636+
return False
637+
638+
exclusion_set = compute_radical(self.exclusion + other.inclusion)
639+
for f in other.exclusion.gens():
640+
if f not in exclusion_set:
641+
return False
642+
643+
return True
644+
645+
def is_empty(self):
646+
return self.contains(Restriction(self.base_ring).intersection([1]))
647+
648+
def __str__(self):
649+
return f"Quasi-Affine variety defined by X - Y where X is \n {self.inclusion} and Y is \n {self.exclusion}"
570650

571651
class ACSVException(Exception):
572652
def __init__(self, message, retry=False):

0 commit comments

Comments
 (0)