| | 3681 | |
|---|
| | 3682 | def height(self, precision=53): |
|---|
| | 3683 | """ |
|---|
| | 3684 | Returns the real height of this elliptic curve. |
|---|
| | 3685 | This is used in integral_points() |
|---|
| | 3686 | |
|---|
| | 3687 | |
|---|
| | 3688 | INPUT: |
|---|
| | 3689 | |
|---|
| | 3690 | precision -- (integer: default 53) bit precision of the |
|---|
| | 3691 | field of real numbers in which the result will lie |
|---|
| | 3692 | |
|---|
| | 3693 | EXAMPLES: |
|---|
| | 3694 | sage: E=EllipticCurve('5077a1') |
|---|
| | 3695 | sage: E.height() |
|---|
| | 3696 | 17.4513334798896 |
|---|
| | 3697 | sage: E.height(100) |
|---|
| | 3698 | 17.451333479889612702508579399 |
|---|
| | 3699 | sage: E=EllipticCurve([0,0,0,0,1]) |
|---|
| | 3700 | sage: E.height() |
|---|
| | 3701 | 1.38629436111989 |
|---|
| | 3702 | sage: E=EllipticCurve([0,0,0,1,0]) |
|---|
| | 3703 | sage: E.height() |
|---|
| | 3704 | 7.45471994936400 |
|---|
| | 3705 | |
|---|
| | 3706 | """ |
|---|
| | 3707 | R = RealField(precision) |
|---|
| | 3708 | c4 = self.c4() |
|---|
| | 3709 | c6 = self.c6() |
|---|
| | 3710 | j = self.j_invariant() |
|---|
| | 3711 | log_g2 = R((c4/12)).abs().log() |
|---|
| | 3712 | log_g3 = R((c6/216)).abs().log() |
|---|
| | 3713 | |
|---|
| | 3714 | if j == 0: |
|---|
| | 3715 | h_j = R(1) |
|---|
| | 3716 | else: |
|---|
| | 3717 | h_j = max(log(R(abs(j.numerator()))), log(R(abs(j.denominator())))) |
|---|
| | 3718 | if (self.c4() != 0) and (self.c6() != 0): |
|---|
| | 3719 | h_gs = max(1, log_g2, log_g3) |
|---|
| | 3720 | elif c4 == 0: |
|---|
| | 3721 | if c6 == 0: |
|---|
| | 3722 | return max(1,h_j) |
|---|
| | 3723 | h_gs = max(1, log_g3) |
|---|
| | 3724 | else: |
|---|
| | 3725 | h_gs = max(1, log_g2) |
|---|
| | 3726 | return max(R(1),h_j, h_gs) |
|---|
| | 3727 | |
|---|
| | 3728 | def antilogarithm(self, z, precision=100): |
|---|
| | 3729 | """ |
|---|
| | 3730 | Returns the rational point (if any) associated to this complex |
|---|
| | 3731 | number; the inverse of the elliptic logarithm function. |
|---|
| | 3732 | |
|---|
| | 3733 | INPUT: |
|---|
| | 3734 | z -- a complex number representing an element of |
|---|
| | 3735 | CC/L where L is the period lattice of the elliptic |
|---|
| | 3736 | curve |
|---|
| | 3737 | |
|---|
| | 3738 | precision -- an integer specifying the precision (in bits) which |
|---|
| | 3739 | will be used for the computation |
|---|
| | 3740 | |
|---|
| | 3741 | OUTPUT: The rational point which is the image of z under |
|---|
| | 3742 | the Weierstrass parametrization, if it exists and can |
|---|
| | 3743 | be determined from z with default precision. |
|---|
| | 3744 | |
|---|
| | 3745 | NOTE: This uses the function ellztopoint from the pari library |
|---|
| | 3746 | |
|---|
| | 3747 | TODO: Extend the wrapping of ellztopoint() to allow passing of |
|---|
| | 3748 | the precision parameter. |
|---|
| | 3749 | |
|---|
| | 3750 | """ |
|---|
| | 3751 | |
|---|
| | 3752 | E_pari = self.pari_curve(prec) |
|---|
| | 3753 | try: |
|---|
| | 3754 | coords = E_pari.ellztopoint(z) |
|---|
| | 3755 | if len(coords) == 1: |
|---|
| | 3756 | return self(0) |
|---|
| | 3757 | return self([CC(xy).real().simplest_rational() for xy in coords]) |
|---|
| | 3758 | except TypeError: |
|---|
| | 3759 | raise ValueError, "No rational point computable from z" |
|---|
| | 3760 | |
|---|
| | 3761 | def integral_points(self, mw_base='auto', both_signs=False, verbose=False): |
|---|
| | 3762 | """ |
|---|
| | 3763 | Computes all integral points (up to sign) on this elliptic curve. |
|---|
| | 3764 | |
|---|
| | 3765 | INPUT: |
|---|
| | 3766 | mw_base -- list of EllipticCurvePoint generating the |
|---|
| | 3767 | Mordell-Weil group of E |
|---|
| | 3768 | (default: 'auto' - calls self.gens()) |
|---|
| | 3769 | both_signs -- True/False (default False): if True the |
|---|
| | 3770 | output contains both P and -P, otherwise only |
|---|
| | 3771 | one of each pair. |
|---|
| | 3772 | verbose -- True/False (default False): if True, some |
|---|
| | 3773 | details of the computation are output |
|---|
| | 3774 | |
|---|
| | 3775 | OUTPUT: |
|---|
| | 3776 | A sorted list of all the integral points on E |
|---|
| | 3777 | (up to sign unless both_signs is True) |
|---|
| | 3778 | |
|---|
| | 3779 | NOTES: The complexity increases exponentially in the rank of |
|---|
| | 3780 | curve E. The computation time (but not the output!) |
|---|
| | 3781 | depends on the Mordell-Weil basis. If mw_base is given |
|---|
| | 3782 | but it not a basis for the Mordell-Weil group (modulo |
|---|
| | 3783 | torsion), integral points which are not in the subgroup |
|---|
| | 3784 | generated by the given points will almost certainly not be |
|---|
| | 3785 | listed. |
|---|
| | 3786 | |
|---|
| | 3787 | EXAMPLES: |
|---|
| | 3788 | A curve of rank 3 with no torsion points |
|---|
| | 3789 | |
|---|
| | 3790 | sage: E=EllipticCurve([0,0,1,-7,6]) |
|---|
| | 3791 | sage: P1=E.point((2,0)); P2=E.point((-1,3)); P3=E.point((4,6)) |
|---|
| | 3792 | sage: a=E.integral_points([P1,P2,P3]); a |
|---|
| | 3793 | [(-3 : 0 : 1), (-2 : 3 : 1), (-1 : 3 : 1), (0 : 2 : 1), (1 : 0 : 1), (2 : 0 : 1), (3 : 3 : 1), (4 : 6 : 1), (8 : 21 : 1), (11 : 35 : 1), (14 : 51 : 1), (21 : 95 : 1), (37 : 224 : 1), (52 : 374 : 1), (93 : 896 : 1), (342 : 6324 : 1), (406 : 8180 : 1), (816 : 23309 : 1)] |
|---|
| | 3794 | |
|---|
| | 3795 | sage: a = E.integral_points([P1,P2,P3], verbose=True) |
|---|
| | 3796 | Using mw_basis [(2 : 0 : 1), (4 : 6 : 1), (114/49 : -720/343 : 1)] |
|---|
| | 3797 | e1,e2,e3: -3.01243037259331 1.06582054769620 1.94660982489710 |
|---|
| | 3798 | Minimal eigenvalue of height pairing matrix: 0.472730555831538 |
|---|
| | 3799 | x-coords of points on compact component with -3 <=x<= 1 |
|---|
| | 3800 | set([0, -1, -3, -2, 1]) |
|---|
| | 3801 | x-coords of points on non-compact component with 2 <=x<= 6 |
|---|
| | 3802 | set([2, 3, 4]) |
|---|
| | 3803 | starting search of remaining points using coefficient bound 6 |
|---|
| | 3804 | x-coords of extra integral points: |
|---|
| | 3805 | set([2, 3, 4, 37, 406, 8, 11, 14, 816, 52, 21, 342, 93]) |
|---|
| | 3806 | Total number of integral points: 18 |
|---|
| | 3807 | |
|---|
| | 3808 | It is also possible to not specify mw_base, but then the |
|---|
| | 3809 | Mordell-Weil basis must be computed; this may take much longer |
|---|
| | 3810 | |
|---|
| | 3811 | sage: E=EllipticCurve([0,0,1,-7,6]) |
|---|
| | 3812 | sage: a=E.integral_points(both_signs=True); a |
|---|
| | 3813 | [(-3 : -1 : 1), (-3 : 0 : 1), (-2 : -4 : 1), (-2 : 3 : 1), (-1 : -4 : 1), (-1 : 3 : 1), (0 : -3 : 1), (0 : 2 : 1), (1 : -1 : 1), (1 : 0 : 1), (2 : -1 : 1), (2 : 0 : 1), (3 : -4 : 1), (3 : 3 : 1), (4 : -7 : 1), (4 : 6 : 1), (8 : -22 : 1), (8 : 21 : 1), (11 : -36 : 1), (11 : 35 : 1), (14 : -52 : 1), (14 : 51 : 1), (21 : -96 : 1), (21 : 95 : 1), (37 : -225 : 1), (37 : 224 : 1), (52 : -375 : 1), (52 : 374 : 1), (93 : -897 : 1), (93 : 896 : 1), (342 : -6325 : 1), (342 : 6324 : 1), (406 : -8181 : 1), (406 : 8180 : 1), (816 : -23310 : 1), (816 : 23309 : 1)] |
|---|
| | 3814 | |
|---|
| | 3815 | |
|---|
| | 3816 | An example with negative discriminant: |
|---|
| | 3817 | sage: EllipticCurve('900d1').integral_points() |
|---|
| | 3818 | [(-11 : 27 : 1), (-4 : 34 : 1), (4 : 18 : 1), (16 : 54 : 1)] |
|---|
| | 3819 | |
|---|
| | 3820 | Another example with rank 5 and no torsion points |
|---|
| | 3821 | |
|---|
| | 3822 | sage: E=EllipticCurve([-879984,319138704]) |
|---|
| | 3823 | sage: P1=E.point((540,1188)); P2=E.point((576,1836)) |
|---|
| | 3824 | sage: P3=E.point((468,3132)); P4=E.point((612,3132)) |
|---|
| | 3825 | sage: P5=E.point((432,4428)) |
|---|
| | 3826 | sage: a=E.integral_points([P1,P2,P3,P4,P5]); len(a) # long time (400s!) |
|---|
| | 3827 | 54 |
|---|
| | 3828 | |
|---|
| | 3829 | |
|---|
| | 3830 | NOTES: |
|---|
| | 3831 | - This function uses the algorithm given in [Co1] |
|---|
| | 3832 | REFERENCES: |
|---|
| | 3833 | -[Co1] Cohen H., Number Theory Vol I: Tools and Diophantine Equations |
|---|
| | 3834 | GTM 239, Springer 2007 |
|---|
| | 3835 | AUTHORS: |
|---|
| | 3836 | - Michael Mardaus (2008-07) |
|---|
| | 3837 | - Tobias Nagel (2008-07) |
|---|
| | 3838 | - John Cremona (2008-07) |
|---|
| | 3839 | """ |
|---|
| | 3840 | ##################################################################### |
|---|
| | 3841 | # INPUT CHECK ####################################################### |
|---|
| | 3842 | if not self.is_integral(): |
|---|
| | 3843 | raise ValueError, "integral_points() can only be called on an integral model" |
|---|
| | 3844 | |
|---|
| | 3845 | if mw_base=='auto': |
|---|
| | 3846 | mw_base = self.gens() |
|---|
| | 3847 | r = len(mw_base) |
|---|
| | 3848 | else: |
|---|
| | 3849 | try: |
|---|
| | 3850 | r = len(mw_base) |
|---|
| | 3851 | except TypeError: |
|---|
| | 3852 | raise TypeError, 'mw_base must be a list' |
|---|
| | 3853 | if not all([P.curve() is self for P in mw_base]): |
|---|
| | 3854 | raise ValueError, "points are not on the correct curve" |
|---|
| | 3855 | |
|---|
| | 3856 | tors_points = self.torsion_points() |
|---|
| | 3857 | |
|---|
| | 3858 | # END INPUT-CHECK#################################################### |
|---|
| | 3859 | ##################################################################### |
|---|
| | 3860 | |
|---|
| | 3861 | ##################################################################### |
|---|
| | 3862 | # INTERNAL FUNCTIONS ################################################ |
|---|
| | 3863 | |
|---|
| | 3864 | ############################## begin ################################ |
|---|
| | 3865 | def point_preprocessing(list): |
|---|
| | 3866 | #Transforms mw_base so that at most one point is on the |
|---|
| | 3867 | #compact component of the curve |
|---|
| | 3868 | Q = [] |
|---|
| | 3869 | mem = -1 |
|---|
| | 3870 | for i in range(0,len(list)): |
|---|
| | 3871 | if not list[i].is_on_identity_component(): # i.e. is on "egg" |
|---|
| | 3872 | if mem == -1: |
|---|
| | 3873 | mem = i |
|---|
| | 3874 | else: |
|---|
| | 3875 | Q.append(list[i]+list[mem]) |
|---|
| | 3876 | mem = i |
|---|
| | 3877 | else: |
|---|
| | 3878 | Q.append(list[i]) |
|---|
| | 3879 | if mem != -1: #add last point, which is not in egg, to Q |
|---|
| | 3880 | Q.append(2*list[mem]) |
|---|
| | 3881 | return Q |
|---|
| | 3882 | ############################## end ################################ |
|---|
| | 3883 | ############################## begin ################################ |
|---|
| | 3884 | def modified_height(i):#computes modified height if base point i |
|---|
| | 3885 | return max(mw_base[i].height(),h_E,c7*mw_base_log[i]**2) |
|---|
| | 3886 | ############################## end ################################ |
|---|
| | 3887 | ############################## begin ################################ |
|---|
| | 3888 | def integral_x_coords_in_interval(xmin,xmax): |
|---|
| | 3889 | """ |
|---|
| | 3890 | Returns the set of integers x with xmin<=x<=xmax which are |
|---|
| | 3891 | x-coordinates of points on this curve. |
|---|
| | 3892 | """ |
|---|
| | 3893 | return set([x for x in range(xmin,xmax) if self.is_x_coord(x)]) |
|---|
| | 3894 | ############################## end ################################ |
|---|
| | 3895 | ############################## begin ################################ |
|---|
| | 3896 | def integral_points_with_bounded_mw_ceoffs(): |
|---|
| | 3897 | r""" |
|---|
| | 3898 | Returns the set of integers x which are x-coordinates of |
|---|
| | 3899 | points on the curve which are linear combinations of the |
|---|
| | 3900 | generators (basis and torsion points) with coefficients |
|---|
| | 3901 | bounded by $H_q$. The bound $H_q$ will be computed at |
|---|
| | 3902 | runtime. |
|---|
| | 3903 | """ |
|---|
| | 3904 | from sage.misc.all import cartesian_product_iterator |
|---|
| | 3905 | from sage.groups.generic import multiples |
|---|
| | 3906 | xs=set() |
|---|
| | 3907 | N=H_q |
|---|
| | 3908 | |
|---|
| | 3909 | def use(P): |
|---|
| | 3910 | """ |
|---|
| | 3911 | Helper function to record x-coord of a point if integral. |
|---|
| | 3912 | """ |
|---|
| | 3913 | if not P.is_zero(): |
|---|
| | 3914 | xP = P[0] |
|---|
| | 3915 | if xP.is_integral(): |
|---|
| | 3916 | xs.add(xP) |
|---|
| | 3917 | |
|---|
| | 3918 | def use_t(R): |
|---|
| | 3919 | """ |
|---|
| | 3920 | Helper function to record x-coords of a point +torsion if integral. |
|---|
| | 3921 | """ |
|---|
| | 3922 | for T in tors_points: |
|---|
| | 3923 | use(R+T) |
|---|
| | 3924 | |
|---|
| | 3925 | # We use a naive method when the number of possibilities is small: |
|---|
| | 3926 | |
|---|
| | 3927 | if r==1 or N<=10: |
|---|
| | 3928 | for P in multiples(mw_base[0],N+1): |
|---|
| | 3929 | use_t(P) |
|---|
| | 3930 | return xs |
|---|
| | 3931 | |
|---|
| | 3932 | # Otherwise is is very very much faster to first compute |
|---|
| | 3933 | # the linear combinations over RR, and only compte them as |
|---|
| | 3934 | # rational points if they are approximately integral |
|---|
| | 3935 | |
|---|
| | 3936 | def is_approx_integral(P): |
|---|
| | 3937 | return (abs(P[0]-P[0].round()))<0.001 and (abs(P[1]-P[1].round()))<0.001 |
|---|
| | 3938 | |
|---|
| | 3939 | RR = RealField() #(100) |
|---|
| | 3940 | ER = self.change_ring(RR) |
|---|
| | 3941 | Rgens = [ER.lift_x(P[0]) for P in mw_base] |
|---|
| | 3942 | for i in range(r): |
|---|
| | 3943 | if abs(Rgens[i][1]-mw_base[i][1])>abs((-Rgens[i])[1]-mw_base[i][1]): |
|---|
| | 3944 | Rgens[i] = -Rgens[i] |
|---|
| | 3945 | for ni in cartesian_product_iterator([range(-N,N+1) for i in range(r-1)]+[range(N+1)]): |
|---|
| | 3946 | RP=sum([ni[i]*Rgens[i] for i in range(r)],ER(0)) |
|---|
| | 3947 | for T in tors_points: |
|---|
| | 3948 | if is_approx_integral(RP+ER(T)): |
|---|
| | 3949 | P = sum([ni[i]*mw_base[i] for i in range(r)],T) |
|---|
| | 3950 | use(P) |
|---|
| | 3951 | return xs |
|---|
| | 3952 | |
|---|
| | 3953 | # Below this point we keep earlier experimental code which |
|---|
| | 3954 | # is slower when either N or r is large |
|---|
| | 3955 | |
|---|
| | 3956 | # if r==2: |
|---|
| | 3957 | # for P in multiples(mw_base[0],N+1): |
|---|
| | 3958 | # for Q in multiples(mw_base[1],N+1): |
|---|
| | 3959 | # for R in set([Q+P,Q-P]): |
|---|
| | 3960 | # use_t(R) |
|---|
| | 3961 | # return xs |
|---|
| | 3962 | # |
|---|
| | 3963 | # if r==3: |
|---|
| | 3964 | # for P in multiples(mw_base[0],N+1): |
|---|
| | 3965 | # for Q in multiples(mw_base[1],N+1): |
|---|
| | 3966 | # PQ = [P+Q,P-Q] |
|---|
| | 3967 | # PQ = set(PQ + [-R for R in PQ]) # {\pm P\pm Q} |
|---|
| | 3968 | # for R in multiples(mw_base[2],N+1): |
|---|
| | 3969 | # for S in PQ: |
|---|
| | 3970 | # use_t(R+S) |
|---|
| | 3971 | # return xs |
|---|
| | 3972 | # |
|---|
| | 3973 | # # general rank |
|---|
| | 3974 | # mults=[list(multiples(mw_base[i],N+1)) for i in range(r)] |
|---|
| | 3975 | # for i in range(r-1): |
|---|
| | 3976 | # mults[i] = [-P for P in mults[i] if not P.is_zero()] + mults[i] |
|---|
| | 3977 | # for Pi in cartesian_product_iterator(mults): |
|---|
| | 3978 | # use_t(sum(Pi,self(0))) |
|---|
| | 3979 | # return xs |
|---|
| | 3980 | # |
|---|
| | 3981 | # older, even slower code: |
|---|
| | 3982 | # |
|---|
| | 3983 | # for i in range(ceil(((2*H_q+1)**r)/2)): |
|---|
| | 3984 | # koeffs = Z(i).digits(base=2*H_q+1) |
|---|
| | 3985 | # koeffs = [0]*(r-len(koeffs)) + koeffs # pad with 0s |
|---|
| | 3986 | # P = sum([(koeffs[j]-H_q)*mw_base[j] for j in range(r)],self(0)) |
|---|
| | 3987 | # for Q in tors_points: # P + torsion points (includes 0) |
|---|
| | 3988 | # tmp = P + Q |
|---|
| | 3989 | # if not tmp.is_zero(): |
|---|
| | 3990 | # x = tmp[0] |
|---|
| | 3991 | # if x.is_integral(): |
|---|
| | 3992 | # xs.add(x) |
|---|
| | 3993 | # return xs |
|---|
| | 3994 | ############################## end ################################# |
|---|
| | 3995 | |
|---|
| | 3996 | # END Internal functions ############################################# |
|---|
| | 3997 | ###################################################################### |
|---|
| | 3998 | |
|---|
| | 3999 | if (r == 0): |
|---|
| | 4000 | int_points = [P for P in tors_points if not P.is_zero()] |
|---|
| | 4001 | int_points = [P for P in int_points if P[0].is_integral()] |
|---|
| | 4002 | if not both_signs: |
|---|
| | 4003 | xlist = set([P[0] for P in int_points]) |
|---|
| | 4004 | int_points = [self.lift_x(x) for x in xlist] |
|---|
| | 4005 | int_points.sort() |
|---|
| | 4006 | if verbose: |
|---|
| | 4007 | print 'Total number of integral points:',len(int_points) |
|---|
| | 4008 | return int_points |
|---|
| | 4009 | |
|---|
| | 4010 | |
|---|
| | 4011 | g2 = self.c4()/12 |
|---|
| | 4012 | g3 = self.c6()/216 |
|---|
| | 4013 | disc = self.discriminant() |
|---|
| | 4014 | j = self.j_invariant() |
|---|
| | 4015 | b2 = self.b2() |
|---|
| | 4016 | |
|---|
| | 4017 | Qx = rings.PolynomialRing(RationalField(),'x') |
|---|
| | 4018 | pol = Qx([-self.c6()/216,-self.c4()/12,0,4]) |
|---|
| | 4019 | if disc > 0: # two real component -> 3 roots in RR |
|---|
| | 4020 | #on curve 897e4, only one root is found with default precision! |
|---|
| | 4021 | RR = R |
|---|
| | 4022 | prec = RR.precision() |
|---|
| | 4023 | ei = pol.roots(RR,multiplicities=False) |
|---|
| | 4024 | while len(ei)<3: |
|---|
| | 4025 | prec*=2 |
|---|
| | 4026 | RR=RealField(prec) |
|---|
| | 4027 | ei = pol.roots(RR,multiplicities=False) |
|---|
| | 4028 | e1,e2,e3 = ei |
|---|
| | 4029 | if r >= 2: #preprocessing of mw_base only necessary if rank > 1 |
|---|
| | 4030 | mw_base = point_preprocessing(mw_base) #at most one point in |
|---|
| | 4031 | #E^{egg}, saved in P_egg |
|---|
| | 4032 | |
|---|
| | 4033 | elif disc < 0: # one real component => 1 root in RR (=: e3), |
|---|
| | 4034 | # 2 roots in C (e1,e2) |
|---|
| | 4035 | roots = pol.roots(C,multiplicities=False) |
|---|
| | 4036 | e3 = pol.roots(R,multiplicities=False)[0] |
|---|
| | 4037 | roots.remove(e3) |
|---|
| | 4038 | e1,e2 = roots |
|---|
| | 4039 | |
|---|
| | 4040 | e = R(1).exp() |
|---|
| | 4041 | pi = R(constants.pi) |
|---|
| | 4042 | |
|---|
| | 4043 | if verbose: |
|---|
| | 4044 | print "Using mw_basis ",mw_base |
|---|
| | 4045 | print "e1,e2,e3: ",e1,e2,e3 |
|---|
| | 4046 | |
|---|
| | 4047 | # Algorithm presented in [Co1] |
|---|
| | 4048 | h_E = self.height() |
|---|
| | 4049 | w1, w2 = self.period_lattice().basis() |
|---|
| | 4050 | mu = R(disc).abs().log() / 6 |
|---|
| | 4051 | if j!=0: |
|---|
| | 4052 | mu += max(R(1),R(j).abs().log()) / 6 |
|---|
| | 4053 | if b2!=0: |
|---|
| | 4054 | mu += max(R(1),R(b2).abs().log()) |
|---|
| | 4055 | mu += log(R(2)) |
|---|
| | 4056 | else: |
|---|
| | 4057 | mu += 1 |
|---|
| | 4058 | |
|---|
| | 4059 | c1 = (mu + 2.14).exp() |
|---|
| | 4060 | M = self.height_pairing_matrix(mw_base) |
|---|
| | 4061 | c2 = min(M.charpoly ().roots(multiplicities=False)) |
|---|
| | 4062 | if verbose: |
|---|
| | 4063 | print "Minimal eigenvalue of height pairing matrix: ", c2 |
|---|
| | 4064 | |
|---|
| | 4065 | c3 = (w1**2)*R(b2).abs()/48 + 8 |
|---|
| | 4066 | c5 = (c1*c3).sqrt() |
|---|
| | 4067 | c7 = abs((3*pi)/((w1**2) * (w1/w2).imag())) |
|---|
| | 4068 | |
|---|
| | 4069 | mw_base_log = [] #contains \Phi(Q_i) |
|---|
| | 4070 | mod_h_list = [] #contains h_m(Q_i) |
|---|
| | 4071 | c9_help_list = [] |
|---|
| | 4072 | for i in range(0,r): |
|---|
| | 4073 | mw_base_log.append(mw_base[i].elliptic_logarithm().abs()) |
|---|
| | 4074 | mod_h_list.append(modified_height(i)) |
|---|
| | 4075 | c9_help_list.append(sqrt(mod_h_list[i])/mw_base_log[i]) |
|---|
| | 4076 | |
|---|
| | 4077 | c8 = max(e*h_E,max(mod_h_list)) |
|---|
| | 4078 | c9 = e/c7.sqrt() * min(c9_help_list) |
|---|
| | 4079 | n=r+1 |
|---|
| | 4080 | c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * misc.prod(mod_h_list)) |
|---|
| | 4081 | |
|---|
| | 4082 | top = 128 #arbitrary first upper bound |
|---|
| | 4083 | bottom = 0 |
|---|
| | 4084 | log_c9=log(c9); log_c5=log(c5) |
|---|
| | 4085 | log_r_top = log(R(r*(10**top))) |
|---|
| | 4086 | # if verbose: |
|---|
| | 4087 | # print "[bottom,top] = ",[bottom,top] |
|---|
| | 4088 | |
|---|
| | 4089 | while R(c10*(log_r_top+log_c9)*(log(log_r_top)+h_E+log_c9)**(n+1)) > R(c2/2 * (10**top)**2 - log_c5): |
|---|
| | 4090 | #initial bound 'top' too small, upshift of search interval |
|---|
| | 4091 | bottom = top |
|---|
| | 4092 | top = 2*top |
|---|
| | 4093 | while top >= bottom: #binary-search like search for fitting exponent (bound) |
|---|
| | 4094 | # if verbose: |
|---|
| | 4095 | # print "[bottom,top] = ",[bottom,top] |
|---|
| | 4096 | bound = floor(bottom + (top - bottom)/2) |
|---|
| | 4097 | log_r_bound = log(R(r*(10**bound))) |
|---|
| | 4098 | if R(c10*(log_r_bound+log_c9)*(log(log_r_bound)+h_E+log_c9)**(n+1)) > R(c2/2 * (10**bound)**2 - log_c5): |
|---|
| | 4099 | bottom = bound + 1 |
|---|
| | 4100 | else: |
|---|
| | 4101 | top = bound - 1 |
|---|
| | 4102 | |
|---|
| | 4103 | H_q = R(10)**bound |
|---|
| | 4104 | break_cond = 0 #at least one reduction step |
|---|
| | 4105 | #reduction via LLL |
|---|
| | 4106 | while break_cond < 0.9: #as long as the improvement of the new bound in comparison to the old is greater than 10% |
|---|
| | 4107 | c = R((H_q**n)*10) #c has to be greater than H_q^n |
|---|
| | 4108 | M = matrix.MatrixSpace(Z,n) |
|---|
| | 4109 | m = M.identity_matrix() |
|---|
| | 4110 | for i in range(r): |
|---|
| | 4111 | m[i, r] = R(c*mw_base_log[i]).round() |
|---|
| | 4112 | m[r,r] = R(c*w1).round() |
|---|
| | 4113 | |
|---|
| | 4114 | #LLL - implemented in sage - operates on rows not on columns |
|---|
| | 4115 | m_LLL = m.LLL() |
|---|
| | 4116 | m_gram = m_LLL.gram_schmidt()[0] |
|---|
| | 4117 | b1_norm = R(m_LLL.row(0).norm()) |
|---|
| | 4118 | |
|---|
| | 4119 | #compute constant c1 ~ c1_LLL of Corollary 2.3.17 and hence d(L,0)^2 ~ d_L_0 |
|---|
| | 4120 | c1_LLL = -1 |
|---|
| | 4121 | for i in range(n): |
|---|
| | 4122 | tmp = R(b1_norm/(m_gram.row(i).norm())) |
|---|
| | 4123 | if tmp > c1_LLL: |
|---|
| | 4124 | c1_LLL = tmp |
|---|
| | 4125 | |
|---|
| | 4126 | if c1_LLL < 0: |
|---|
| | 4127 | raise RuntimeError, 'Unexpected intermediate result. Please try another Mordell-Weil base' |
|---|
| | 4128 | |
|---|
| | 4129 | d_L_0 = R(b1_norm**2 / c1_LLL) |
|---|
| | 4130 | |
|---|
| | 4131 | #Reducing of upper bound |
|---|
| | 4132 | Q = r * H_q**2 |
|---|
| | 4133 | T = (1 + (3/2*r*H_q))/2 |
|---|
| | 4134 | if d_L_0 < R(T**2+Q): |
|---|
| | 4135 | d_L_0 = 10*(T**2*Q) |
|---|
| | 4136 | low_bound = R((sqrt(d_L_0 - Q) - T)/c) |
|---|
| | 4137 | |
|---|
| | 4138 | #new bound according to low_bound and upper bound |
|---|
| | 4139 | #[c_5 exp((-c_2*H_q^2)/2)] provided by Corollary 8.7.3 |
|---|
| | 4140 | if low_bound != 0: |
|---|
| | 4141 | |
|---|