|
119 | 119 | from sage.algebras.weyl_algebra import DifferentialWeylAlgebra |
120 | 120 | from sage.arith.misc import gcd |
121 | 121 | from sage.arith.srange import srange |
| 122 | +from sage.combinat.combination import Combinations |
122 | 123 | from sage.functions.log import log, exp |
123 | 124 | from sage.functions.other import factorial |
124 | 125 | from sage.matrix.constructor import matrix |
@@ -662,19 +663,8 @@ def diagonal_asymptotics_combinatorial( |
662 | 663 | H = R(SR(H)) |
663 | 664 | vs = [R(SR(v)) for v in vs] |
664 | 665 | 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) |
678 | 668 | s = len(factors) |
679 | 669 | normals = matrix( |
680 | 670 | [[f.derivative(v).subs(subs_dict) for v in vs] for f in factors] |
@@ -706,67 +696,12 @@ def diagonal_asymptotics_combinatorial( |
706 | 696 | else: |
707 | 697 | raise ACSVException("Cannot find parametrizing set.") |
708 | 698 |
|
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 |
733 | 702 | ) |
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 |
757 | 703 | ) |
758 | 704 |
|
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 | | - |
770 | 705 | asm_vals = [(c, d, b.sqrt(), a, s) for a, b, c, d, s in asm_quantities] |
771 | 706 |
|
772 | 707 | if as_symbolic: |
@@ -813,7 +748,156 @@ def diagonal_asymptotics_combinatorial( |
813 | 748 |
|
814 | 749 | return result |
815 | 750 |
|
| 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()) |
816 | 758 |
|
| 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 | + |
817 | 901 | def _general_term_asymptotics(G, H, r, vs, cp, expansion_precision): |
818 | 902 | r""" |
819 | 903 | Compute coefficients of general (not necessarily leading) terms of |
@@ -1734,3 +1818,20 @@ def _prepare_expanded_polynomial_ring(variables, direction=None, include_t=True) |
1734 | 1818 | replaced_direction, |
1735 | 1819 | direction_variable_values, |
1736 | 1820 | ) |
| 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 |
0 commit comments