UBC Theses and Dissertations

UBC Theses Logo

UBC Theses and Dissertations

Implementation of a Thue-Mahler equation solver Hambrook, Kyle David 2011

Your browser doesn't seem to have a PDF viewer, please download the PDF to view this item.

Item Metadata

Download

Media
24-ubc_2011_fall_hambrook_kyle.pdf [ 721.04kB ]
Metadata
JSON: 24-1.0072341.json
JSON-LD: 24-1.0072341-ld.json
RDF/XML (Pretty): 24-1.0072341-rdf.xml
RDF/JSON: 24-1.0072341-rdf.json
Turtle: 24-1.0072341-turtle.txt
N-Triples: 24-1.0072341-rdf-ntriples.txt
Original Record: 24-1.0072341-source.json
Full Text
24-1.0072341-fulltext.txt
Citation
24-1.0072341.ris

Full Text

IMPLEMENTATION OF A THUE-MAHLER EQUATION SOLVER  by KYLE DAVID HAMBROOK  A THESIS SUBMITTED IN PARTIAL FULFILLMENT OF THE REQUIREMENTS FOR THE DEGREE OF MASTER OF SCIENCE in THE FACULTY OF GRADUATE STUDIES (Mathematics)  THE UNIVERSITY OF BRITISH COLUMBIA (Vancouver)  October 2011  c Kyle David Hambrook, 2011  Abstract A practical algorithm for solving an arbitrary Thue-Mahler equation is presented, and its correctness is proved. Methods of algebraic number theory are used to reduce the problem of solving the Thue-Mahler equation to the problem of solving a finite collection of related Diophantine equations having parameters in an algebraic number field. Bounds on the solutions of these equations are computed by employing the theory of linear forms in logarithms of algebraic numbers. Computational Diophantine approximation techniques based on lattice basis reduction are used to reduce the upper bounds to the point where a direct enumerative search of the solution space becomes possible. Such an enumerative search is carried out with the aid of a sieving procedure to finally determine the complete set of solutions of the Thue-Mahler equation. The algorithm is implemented in full generality as a function in the Magma computer algebra system. This is the first time a completely general algorithm for solving Thue-Mahler equations has been implemented as a computer program.  ii  Table of contents Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  ii  Table of contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  iii  Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  iv  Dedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  v  1  Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  1  2  Decompositions of primes and polynomials; p-adic embeddings; p-adic valuations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  6  3  First steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  8  4  The prime ideal removing lemma . . . . . . . . . . . . . . . . . . . . . . . . 10  5  Factorization of the Thue-Mahler equation . . . . . . . . . . . . . . . . . . . 14  6  The S-unit equation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17  7  The p-adic logarithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20  8  A small upper bound for nl in a special case . . . . . . . . . . . . . . . . . . 22  9  Choosing the indices j and k in the pl -adic cases . . . . . . . . . . . . . . . 25  10  The general strategy for bounding the ni and the ai . . . . . . . . . . . . . 27  11  A lower bound for linear forms in p-adic logarithms . . . . . . . . . . . . . . 28  12  A lower bound for linear forms in real/complex logarithms . . . . . . . . . . 30  13  A bound for nl in terms of log H . . . . . . . . . . . . . . . . . . . . . . . . 31  14  A bound for A when min x − yθ(i) is large . . . . . . . . . . . . . . . . . 33  15  A bound for A when min x − yθ(i) is small . . . . . . . . . . . . . . . . . 36  16  A bound for H . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41  17  The reduction strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42  18  Lattice basis reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43  19  Preliminaries for the pl -adic reduction procedure . . . . . . . . . . . . . . . 45  20  Basic pl -adic reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48  21  Basic real reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52  22  Refined pl -adic reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59  23  Refined real reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65  24  The sieving procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70  25  Conclusion  1≤i≤n  1≤i≤n  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72  References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Appendix: The implementation in Magma . . . . . . . . . . . . . . . . . . . . . . 79  iii  Acknowledgements I am indebted to Dr. Michael A. Bennett for suggesting to me the line of research on which this thesis is based and for numerous comments and suggestions that helped me to improve this thesis. I also thank Dr. Dragos Ghioca for helping me to improve the style of this thesis. This research was funded in part by a National Sciences and Engineering Research Council Postgraduate Scholarship and a Li Tze Fong Memorial Fellowship.  iv  Dedication  To my mom.  v  1  Introduction A Thue-Mahler equation is an equation of the form F (x, y) = apz11 · · · pzvv ,  (1)  where F is an irreducible binary form over Z of degree n ≥ 3, a is a nonzero integer, p1 , . . . , pv are rational primes, and the unknowns x, y, z1 , . . . , zv are integers with (x, y) = 1 and zi ≥ 0 (i = 1, . . . , v). Thue-Mahler equations generalize Thue equations, which are simply equations of the form F (x, y) = a without the condition (x, y) = 1. The condition (x, y) = 1 in the definition of a Thue-Mahler equation is important, for without it every Thue-Mahler equation with at least one solution would trivially have infinitely many solutions. In 1933, Mahler [Mah] proved that an arbitrary Thue-Mahler equation has only finitely many solutions. His proof was ineffective in the sense that it provided no means to actually find the solutions. In the mid-1960s, Baker proved his ground-breaking results on effective lower bounds for linear forms in logarithms of algebraic numbers. By generalizing Baker’s results to the p-adic case, it was proved by Sprindˇzuk and Vinogradov [SV] and by Coates [Coa1], [Coa2] that the solutions of any Thue-Mahler equation could, at least in principle, be determined effectively. The first general ideas on the practical computation of the solutions of an arbitrary Thue-Mahler equation are due to Tzanakis and de Weger (cf. [dW1], [dW2], [TW1], [TW2]). These ideas were inspired in part by the method that Agrawal, Coates, Hunt, and van der Poorten used in [ACHP] to solve a specific Thue-Mahler equation. In [TW2], Tzanakis and de Weger gave a practical procedure for finding all the solutions of an arbitrary Thue-Mahler equation. Up until now, no general algorithm for solving an arbitrary Thue-Mahler equation had been implemented as a computer program. Anyone wishing to solve a Thue-Mahler equation would need to apply the method of [TW2] (or a more specialized method if the equation was of a special form) to the equation themselves. The numerous computational tasks involved in the method would, of course, be performed with the assistance of a computer, but the set-up for these tasks could represent a significant challenge to the would-be solver. The main novel contribution of this thesis is the implementation of a modified version of Tzanakis and de Weger’s procedure for solving an arbitrary ThueMahler equation as a computer program. Hence, to solve a given Thue-Mahler equation now, one only needs to enter the parameters of the equation into our program and wait for the list of solutions to be returned. 1  Following [TW2], we present in this thesis a practical algorithm for finding all the solutions of an arbitrary Thue-Mahler equation. The general outline of the algorithm consists of six steps. Step 1. We reduce the problem of solving the given Thue-Mahler equation to the problem of solving a collection of finitely many Diophantine equations whose defining parameters belong to a certain algebraic number field K. The collection is such that if we know the solutions of each equation in the collection, then we can easily derive all of the solutions of the Thue-Mahler equation. So this is a reduction indeed. The principle computational work here consists of: computing some data for K (including an integral basis, a system of fundamental units, and a splitting field); computing the factorizations of the primes p1 , ..., pv into prime ideals in the ring of integers of K; finding the roots of the defining polynomial of K in C and in the algebraic closure of the p-adic field Qp for p ∈ {p1 , ..., pv }; applying a lemma of Tzanakis and de Weger to ensure that the collection of Diophantine equations that we will need to solve is small; and, finally, computing the defining parameters of these Diophantine equations. We perform the next four steps for each of the Diophantine equations in our collection. Step 2. We perform numerous p-adic computations to make optimal choices for certain parameters which arise and (whenever possible) to either determine exact values for or find small bounds on certain variables involved in the Diophantine equation under consideration. These computations, in general, ultimately reduce the amount of computation needed in subsequent steps. Specifically, we (potentially) reduce the number of linear forms that need to be considered considered in Steps 3 and 4, as well as reduce the number of terms in the linear forms that are considered. This results in smaller bounds and fewer computations in Step 3, in lower dimensional and fewer approximation lattices in Step 4, and in a smaller number of candidate solutions to test in Step 5. All of these features help to decrease the overall computation involved in Steps 3-5. The individual computations involved in this step are not very difficult (the most involved being probably the evaluation of p-adic logarithms), but if there are many possibilities for the parameters, this step could take some time. However, it is very unlikely that the computational cost of this step is anywhere near that of the most costly steps in the algorithm.  2  Step 3. We use the theory of linear forms in real/complex and p-adic logarithms of algebraic numbers to derive very large bounds on those variables in the Diophantine equation that were not bounded in the previous step. For this purpose we use the best theorems available. In the real/complex case we appeal to the results of Matveev [Mat], and in the p-adic case we employ the results of Yu [Yu2]. The most difficult computations for this step involve factoring rational primes into ideals in the splitting field of K, constructing a specific subfield of the splitting field, and computing heights of specific elements of the splitting field. Step 4. We drastically reduce the upper bounds derived in Step 3 by using computational Diophantine approximation techniques. These techniques involve applying LLLlattice basis reduction methods to approximation lattices associated with the linear forms in logarithms considered in Step 3. The main computations here involve using the LLL algorithm to compute an LLL-reduced basis for a given lattice and using the Fincke-Pohst algorithm to enumerate all the short vectors in a given lattice. Step 5. We use a sieving procedure to find all the solutions of the Diophantine equation that live in the box defined by the bounds derived in the previous three steps. The procedure essentially works by first running through all the possible solutions in the box and ‘sieving’ out the vast majority of non-solutions by checking congruence conditions that have relatively low computational cost to check, and then testing the small number of possible solutions that remain for the Diophantine equation directly. Though we expect the bounds defining the box to be small, there can still be a very large number of possible solutions to check (especially if the number of primes involved in the Thue-Mahler equation is large and/or the number of elements in a system of fundamental units for K is large). The computations performed on each individual candidate solution are relatively simple, but the sheer number of candidates often makes this step the computational bottleneck of the entire algorithm. Step 6. Having performed Steps 2-5 for each Diophantine equation in our collection, we now know all the solutions of each such equation, and we use this knowledge to determine all the solutions of the Thue-Mahler equation. The individual computations involved in this step are practically trivial, and there should not be very many to do. 3  The above steps more or less accurately describe our algorithm for solving an arbitrary Thue-Mahler equation. However, we have omitted two important details in order to make the algorithm easier to understand upon first reading. The first omitted detail is that during Step 4 we will likely accumulate a number of explicitly known exceptional candidate solutions that don’t fit in the final reduced box that we will run through in Step 5. Since we know them explicitly, these exceptional candidates don’t hold us back from reducing the size of the box, but we must test them as solutions of the Thue-Mahler equation separately. The second omitted detail is that, instead of waiting to perform Step 6 until after Step 5 has been performed for every equation in the collection, we will essentially perform a portion of Step 6 at the end of each Step 5. More explicitly, as we are finding the solutions of each Diophantine equation, we will also find the corresponding solutions of the Thue-Mahler equation. We do this to improve efficiency. We mentioned above that Step 5 could be the main bottleneck for the algorithm. This will be the case in general except possibly when the degree of K (which is the degree of F (x, y)) is large or when the degree of the splitting field of K is very large. When the degree of K is large, computing a system of fundamental units and/or performing certain other necessary computations in K can be extremely time consuming. In particular, the worst-case complexity of calculating a system of fundamental units is exponential in the degree of K. Performing the necessary computations in the splitting field of K can likewise be very difficult if the splitting field has large degree. It is difficult to say much about the precise computational complexity of the algorithm without delving into a very complicated analysis. However, since the sieving process will often be the computational bottleneck for the algorithm, we feel it is important to give a rough estimate of its running time. Let E(k) denote the time required for modular exponentiation when the exponent is a k-bit integer and M (k) denotes the time required to multiply two k-bit integers. It is reasonable to assume E(k) = O(k) and M (k) = O(k 2 ). The running time for our implementation of the sieve procedure is roughly O (E(d−1 log N ) + M (n−1 N 1/d ))dN bit operations, where N is the total number of tuples that need to be searched through, n is the degree of K, and d is the sum of the number v of rational primes in the Thue-Mahler equation and the number r of elements in a complete set of fundamental units for K. Note that N will depend exponentially on d. The algorithm lends itself well to being implemented in parallel in a master/slave paradigm as follows. The master process performs Step 1 and then, for each Diophantine  4  equation in the collection it builds, farms out Steps 2-5 to a slave. Once the slaves are done, each slave passes back the list of solutions for its Diophantine equation to the master process, and the master process performs Step 6. Alternatively, each slave could perform a part of Step 6 itself after finishing Step 5 as discussed above. Our algorithm is very similar to that of Tzanakis and de Weger [TW2]. Indeed, the overall strategy is the same and every Lemma and Theorem that we present appears (at least implicitly) in [TW2]. However, our algorithm does differ from Tzanakis and de Weger’s in a few minor ways that can potentially result in significant computational savings. One difference is that our algorithm puts more work into minimizing how often the most computationally expensive techniques are employed; this work is mostly done in Step 2 above. Another difference is that our algorithm does more work to optimize the bounds arising from the theory of linear forms in logarithms. We have endeavoured to present the algorithm essentially in the manner in which it is implemented. As a consequence, our exposition differs from [TW2] in both overall structure and in the increased level of practical detail provided in the various steps. The implementation of our algorithm as a function in the Magma computer algebra system [BCP] can be found in the Appendix.  5  2  Decompositions of primes and polynomials; p-adic embeddings; p-adic valuations In this section, we give a concise description of the relationships between how a rational  prime p decomposes in the ring of integers of a number field K, how the defining polynomial of K decomposes over the field Qp of p-adic numbers, how K embeds into the algebraic closure of Qp , and how the p-adic valuation on Q extends to a p-adic valuation on K. We also discuss how the p-adic valuation on Qp extends to larger fields. As references for this material we give [BS] (especially Theorem 3 in Chapter 4, Section 2), [Ca] (especially Lemma 2.1 in Chapter 9), [Ha] (especially Chapter 18), [Ko] (especially Chapter 3, Section 2), and [Na] (especially Theorem 6.1). Let p be a rational prime. Let g(t) be an irreducible polynomial in Q[t] of degree n, and let K = Q(θ), where g(θ) = 0. There are one-to-one correspondences between each of the following four sets of objects: • The prime ideals in (the ring of integers of) K that divide p. • The irreducible polynomial factors of g(t) in Qp [t]. • The classes of conjugate embeddings of K into the algebraic closure Qp of Qp . • The extensions of the p-adic valuation ordp on Q to K. In what follows, we will describe the important features of these correspondences. Note that two embeddings of K into Qp are called conjugate if they map θ to roots of the same irreducible polynomial in Qp [t]. Note also that what we call a p-adic valuation is sometimes called a p-adic order. Let (p) = pe11 · · · pemm be the decomposition of (p) into prime ideals in OK (the ring of integers of K), and let fi be the residue degree of pi over p. For x ∈ K, let ordpi (x) denote the pi -adic valuation of x, i.e., the exponent of pi in the prime ideal factorization of the (fractional) ideal (x). Let Kpi denote the completion of K with respect to ordpi . Let g(t) = g1 (t) · · · gm (t) be the decomposition of g(t) into irreducible polynomials in Qp [t]. For each i ∈ {1, . . . , m}, let ni = deg gi (t). The correspondence pi ←→ gi (t) is such that ni = ei fi and Kpi  Qp (θi ), 6  where gi (θi ) = 0. There are n embeddings of K into Qp , and each one fixes Q and maps θ to a root of g (1)  (ni )  in Qp . Let θi , . . . , θi  denote the roots of gi (t) in Qp . For i = 1, . . . , m and j = 1, . . . , ni , (j)  (j)  let σij be the embedding of K into Qp (θi ) defined by θ → θi . The m classes of conjugate embeddings are {σi1 , . . . , σini } (i = 1, . . . , m). Note that σij coincides with the embedding K → Kpi  Qp (θi )  (j)  Qp (θi ).  For any finite extension L of Qp , the p-adic valuation on Qp extends uniquely to L as ordp (x) =  1 ordp NL/Qp (x) . [L : Qp ]  (2)  This definition is independent of the field L containing x. So, since each element of Qp is by definition contained in some finite extension of Qp , (2) can be used to define the p-adic valuation of any x ∈ Qp . Every finite extension of Qp is complete with respect to ordp , but Qp is not. The completion of Qp with respect to ordp is denoted by Cp . Note that the formulas ordp (xy) = ordp (x) + ordp (y),  ordp (x + y) ≥ min {ordp (x), ordp (y)}  still hold when x, y ∈ Cp . It is convenient to record here that an element x ∈ Cp having ordp (x) = 0 is called a p-adic unit. The m extensions of the p-adic valuation on Q to K are just multiples of the pi -adic valuations on K: ordp (x) =  1 ordpi (x) ei  (i = 1, . . . m).  We can also view these extensions as arising from the various embeddings of K into Qp . (j)  Indeed, the extension to Qp (θi ) of the p-adic valuation on Qp induces a p-adic valuation on K via the embedding σij as ordp (x) = ordp (σij (x)), and we have ordp (σij (x)) =  1 ordpi (x) ei  (i = 1, . . . , m; j = 1, . . . , ni ).  (3)  7  3  First steps Fix a nonzero integer a and a set of distinct rational primes p1 , . . . , pv . Let F (x, y) = c0 xn + c1 xn−1 y + · · · + cn−1 xy n−1 + cn y n  be an irreducible binary form over Z of degree n ≥ 3. We want to solve the Thue-Mahler equation F (x, y) = apz11 · · · pzvv  (4)  for unknown integers x, y, z1 , . . . , zv with (x, y) = 1 and zi ≥ 0 for i = 1, . . . , v. We will assume that c0 = 1 and that (a, pi ) = 1 for i = 1, . . . , v. The assumption (a, pi ) = 1 for i = 1, . . . , v results in no loss of generality because a tuple (x, y, z1 , . . . , zv ) is a solution of (4) if and only if the tuple (x, y, z1 , . . . , zv ) with zi = zi + ordpi (a) for i = 1, . . . , v is a solution of z  F (x, y) = a p11 · · · pzvv , where a = a/(a, p1 · · · pv ). To see that we can assume c0 = 1 without loss of generality, first note that at least one of c0 and cn is nonzero, and that solving (4) is equivalent to solving C0 X n + C1 X n−1 Y + · · · + Cn−1 XY n−1 + Cn Y n = apz11 · · · pzvv , where Ci = cn−i for i = 0, . . . , n, X = y, and Y = x. These facts clearly imply we can assume c0 = 0. We claim that, under the assumptions (a, pi ) = 1 for i = 1, . . . , v and c0 = 0 (both of which we proved we are free to make), each solution (x, y, z1 , . . . , zv ) of (4) with (x, y) = 1 is such that, for some divisor d of c0 , z  X n + C1 X n−1 Y + · · · + Cn−1 XY n−1 + Cn Y n = a p11 · · · pzvv ,  (X, Y ) = 1  (5)  holds with Ci = ci ci−1 for i = 1, . . . , n, a = a/(a, d), X = c0 x/d, Y = y/d, and zi = 0 zi − ordpi (d) for i = 1, . . . , v. The claim reduces the problem of finding all solutions of (4) with (x, y) = 1 to the problem of finding all the solutions (X, Y, z1 , .., zv ) of (5) for each divisor d of c0 . As the coefficient of X n in (5) is 1, establishing the claim will thus show that we can take c0 = 1 in (4) without loss of generality. To prove the claim, consider any solution (x, y, z1 , . . . , zv ) of (4) with (x, y) = 1, and let d = (c0 , y). Then (c0 x/d, y/d) = 1  8  and d divides apz11 · · · pzvv . The latter fact combined with the assumption (a, pi ) = 1 for i = 1, . . . , v implies apz11 · · · pzvv a z1 −ordp1 (d) z −ordpv (d) . = p · · · pvv d (a, d) 1 On the other hand, multiplying (4) by cn−1 /dn gives 0 c0 x d  n  + c1  c0 x d  n−1  y c0 x + · · · + cn−1 c0n−2 d d z1 n−1 z v c ap · · · pv = 0n−1 1 . d d  y d  n−1  + cn cn−1 0  y d  n  Putting everything together and converting to the notation Ci = ci c0i−1 (i = 1, . . . , n), a = a/(a, d), X = c0 x/d, Y = y/d, and zi = zi − ordpi (d) yields (5), and, therefore, proves the claim. Put g(t) = F (t, 1) = tn + c1 tn−1 + · · · + cn−1 t + cn and note that g(t) is irreducible in Z[t]. Let K = Q(θ) with g(θ) = 0. Then (4) is equivalent to the norm equation NK/Q (x − yθ) = apz11 · · · pzvv .  (6)  Let mi  e  pijij  (pi ) = j=1  be the factorization of pi into prime ideals in the ring of integers OK of K, and let fij be f  the residue degree of pij over pi . Then, since N (pij ) = pi ij , (6) implies finitely many ideal equations of the form m1  z  mv  p1j1j · · ·  (x − yθ) = a j=1  z  pvjvj ,  (7)  j=1  where a is an ideal of norm |a| and the zij are unknown nonnegative integers related to the zi by  mi j=1 fij zij  = zi .  Our first task will be to cut down the number of variables appearing in (7). We will do this by showing that only a few prime ideals can divide (x − yθ) to a large power.  9  4  The prime ideal removing lemma In this section, we establish the key lemma that will allow us to cut down the number  of prime ideals that can appear to a large power in the factorization of (x − yθ). Let p be a rational prime and keep the same notation as in Section 2. Lemma 4.1. (The Prime Ideal Removing Lemma). (a) For every pair i = j ∈ {1, . . . , m}, if (k)  − θj  (k)  − θj  ordpi (x − yθ) > max {ei , ej } min ordp θi k,l  (l)  ,  (8)  (l)  .  (9)  then ordpj (x − yθ) ≤ max {ei , ej } min ordp θi k,l  (b) For every i ∈ {1, . . . , m}, (k)  ordpi (x − yθ) ≤ ei min ordp θi k,l  (l)  − θi  .  (10)  Note that the right-hand side of (10) is finite if and only if ei fi > 1. Proof. Let i, j ∈ {1, . . . , m}. Put vi = ordpi (x − yθ), vj = ordpj (x − yθ). It suffices to show min {vi , vj } (k) (l) ≤ ordp (θi − θj ) max {ei , ej } vi (k) for every k ∈ {1, . . . , ni }, l ∈ {1, . . . , nj }. In view of (3), we have = ordp x − yθi and ei vj (l) = ordp x − yθj . Hence, ej min {vi , vj } ≤ min max {ei , ej }  vi vj , ei ej (k)  = ordp θi If p  (k)  ≤ ordp x − yθi (l)  − θj  (k)  y = ordp θi  (l)  − x − yθj (l)  − θj  + ordp (y).  y, we are done. In case p divides y, each prime ideal above p also divides y. But  a prime ideal dividing y cannot divide (x − yθ) because (x, y) = 1. So if p divides y, the left-hand sides of (8)-(10) are zero.  10  If m > 1, let Di = min  max  1≤j<k≤m  (h)  max {ej , ek } min ordp θj h,l  (l)  − θk  (k)  , ei min ordp θi k,l  (l)  − θi  for i = 1, . . . , m. Corollary 4.2. If m > 1, there is at most one pi dividing p with ordpi (x − yθ) > Di , and it satisfies ei = fi = 1 (if it exists).  Proof. Immediate from Lemma 4.1. Corollary 4.3. There is at most one pi dividing p with ordpi (x − yθ) >  1 max {e1 , . . . , em } ordp (Discrg(t)), 2  (11)  and it satisfies ei = fi = 1 (if it exists). Proof. Let θ(1) , . . . , θ(n) denote the roots of g in Qp . Since (θ(h) − θ(h ) )2 ,  Discr g(t) =  1≤h<h ≤n  and since θ is an algebraic integer, we have 2ordp θ(h) − θ(h ) ≥ 2ordp θ(h) − θ(h )  ordp (Discrg(t)) = 1≤h<h ≤n  for any two distinct roots θ(h) , θ(h ) . So if i = j ∈ {1, . . . , m}, we have ordp (Discrg(t)) ≥ (k)  2ordp θi  (l)  − θj  for all k, l. It follows from this fact and Lemma 4.1(a) that if (11) holds  for some pi , then it fails to hold for every pj with j = i. If a pi has either ei > 1 or (k)  (l)  fi > 1, then there are (at least) two distinct roots θi , θi , and we have ordp (Discrg(t)) ≥ (k)  2ordp θi  (l)  − θi  . It follows from Lemma 4.1(b) that (11) cannot hold for such a pi .  Since Corollary 4.3 is vacuously true when m = 1, one can also deduce Corollary 4.3 from Corollary 4.2 by observing that 1 max {e1 , . . . , em } ordp (Discrg(t)) ≥ Di 2 for every i ∈ {1, . . . , m} when m > 1. 11  In light of the results above, we see that for each solution (x, y, z1 , . . . , zv ) of (4) and each p ∈ {p1 , . . . , pv }, there can be at most one prime ideal pk above p whose exponent in the factorization of (x − yθ) need not be bounded by either  1 2  max {e1 , . . . , em } ordp (Discrg(t))  or Dk . We call such a pk the unconstrained prime above p. We know that the unconstrained prime must have ek = fk = 1. For each choice of unconstrained prime pk above p, there are only finitely many possibilities for the exponents of the other primes above p in the factorization of (x − yθ). If there is no prime ideal pk above p with ek = fk = 1, there can be no unconstrained prime above p, and there are only finitely many possibilities for the exponent of each prime above p in the factorization of (x − yθ). Now we describe an algorithm that, for a given p ∈ {p1 , . . . , pv }, computes for each choice of unconstrained prime above p the set of all possible combinations of exponents that the other primes above p can have in the factorization of (x − yθ). If there can be no unconstrained prime above p (i.e., if there is no prime ideal above p with residue degree and ramification index both equal to 1), the algorithm computes the set of all possible combinations of exponents that the primes above p can have in the factorization of (x−yθ). The Prime Ideal Removing Algorithm. em  Input: One of the primes pl along with its prime ideal factorization (pl ) = pel11 · · · plm l in OK and the residue degrees fi of the pli . Output: If pl has at least one prime ideal plk above it with ek = fk = 1, then for each such prime ideal plk above p with ek = fk = 1, the algorithm outputs the set Ak of all tuples (al1 , . . . , alml ) such that, for each i ∈ {1, . . . , ml } \ {k}, ali is a possible exponent of the prime ideal pli in the factorization of (x − yθ), and such that alk = 0. If there is no prime ideal plk above pl with ek = fk = 1, then the algorithm outputs the set A0 of all tuples (al1 , . . . , alml ), where, for each i ∈ {1, . . . , ml }, ali is a possible exponent of the prime ideal pli in the factorization of (x − yθ). Algorithm: For i = 1, . . . , ml , compute the roots θi1 , . . . , θini of the irreducible factor of g(t) in Qpl [t] that corresponds to pli . For each i, j ∈ {1, . . . , ml }, compute (k)  cij = max {ei , ej } min ordpl θi k,l  (l)  − θj  .  If ml > 1, set Ci = Di for each i ∈ {1, . . . , ml }.  12  If ml = 1, set Ci = min  1 (k) (l) max {e1 , . . . , em } ordp (Discr g(t)), ei min ordp θi − θi k,l 2  for each i ∈ {1, . . . , ml }. IF there is some k ∈ {1, . . . , ml } such that ek = fk = 1 THEN FOR each k ∈ {1, . . . , ml } such that ek = fk = 1 DO //Consider plk as the unconstrained prime above pl . Form the set Ak of all tuples (al1 , . . . , alml ) of nonnegative integers subject to the constraints (a) ali ≤ Ci ,  1≤i≤m  (b) ali > cij ⇒ alj ≤ cij ,  1 ≤ i, j ≤ m, i = j  (c) alk = 0 END FOR ELSE //there is no k ∈ {1, . . . , ml } such that ek = fk = 1. Form the set A0 of all tuples (al1 , . . . , alml ) of nonnegative integers subject to the constraints (a) ali ≤ Ci ,  1≤i≤m  (b) ali > cij ⇒ alj ≤ cij ,  1 ≤ i, j ≤ m, i = j  END IF END FOR Note that the algorithm above is a simplified version of the one we actually implement.  13  5  Factorization of the Thue-Mahler equation Upon running the Prime Ideal Removing Algorithm (see Section 4) for each pi (i =  1, . . . , v), the task of solving the finite set of equations represented by (7) is reduced to the task of solving the set of equations of the form (x − yθ) = abpu1 1 · · · puv v  (12)  in integer variables x, y, u1 , . . . , uv with ui ≥ 0 for i = 1, . . . , v. Here • a is an ideal of OK of norm |a|. • pi is a prime ideal of OK above pi with ramification index and residue degree both equal to 1, provided one exists. If there are no such prime ideals, pi = (1) and ui = 0. • b is an ideal of OK whose prime ideal factors are those that divide one of the pi , but are not equal to one of the pi . • ui + ordpi (N (b)) = zi . To be precise, b is of the form m1  a  mv  p1j1j · · ·  b= j=1  a  pvjvj , j=1  where each (ai1 , . . . , aimi ) is a tuple from the Prime Ideal Removing Lemma Algorithm that corresponds to pi being the unconstrained prime above pi . So, in particular, if pi = pik , we have aik = 0. Of course, we must add the qualification that if there are no primes above pi with ramification index and residue degree both equal to 1, (ai1 , . . . , aimi ) is a tuple from the set A0 output by the Prime Ideal Removing Algorithm. Note ordpi (N (b)) = mi j=1 fij aij .  Consider a particular instance of (12). That is, fix choices for a, b, p1 , . . . , pv . Fix a complete set of fundamental units for OK : ε1 , . . . , εr . Here r = s+t−1, with s denoting the number of real embeddings of K into C, and t denoting the number of complex conjugate pairs of non-real embeddings of K into C. For i = 1, . . . , v, let hi be the smallest positive integer for which phi i is principal and let πi ∈ OK be a generator for phi i . Then (x − yθ) = abps11 · · · psvv (π1n1 ) . . . (πvnv )  (13)  where the unknown integers s1 , . . . , sv , n1 , . . . , nv satisfy ui = hi ni + si ,  ni ≥ 0,  0 ≤ si < hi . 14  Since the si vary in a finite set, we treat them as parameters. Now fix values for s1 , . . . , sv . The ideal abps11 · · · psvv is necessarily principal (because the set of nonzero fractional principal ideals forms a subgroup of the group of nonzero fractional ideals). Fix α ∈ OK such that abps11 · · · psvv = (α). Since (13) is an equality of principal ideals and since generators of principal ideals are determined only up to multiplication by units, we are led to the equation x − yθ = αζεa11 · · · εar r π1n1 · · · πvnv  (14)  with unknowns ai ∈ Z, ni ∈ Z≥0 , and ζ in the set T of roots of unity in OK . Since T is finite, we will treat ζ as another parameter. To summarize, our original problem of solving (4) has been reduced to the problem of solving finitely many equations of the form (14) for the variables x, y,a1 , . . . , ar ,n1 , . . . , nv . Since the πi are determined by the pi , and since α is a fixed generator of abps11 · · · psvv , the parameters in (14) are ζ, a, b, p1 , . . . , pv , s1 , . . . , sv . We must solve (14) for each combination of possible values of these parameters. Note that each solution (x, y, z1 , . . . , zv ) of (4) corresponds to a solution (x, y, n1 , . . . , nv , a1 , . . . , ar ) of some instance of (11), where z i = n i hi + s i + t i  (15)  with ti = ordpi (N (b)). Note that we only need to consider half the elements in T as possible values for the parameter ζ. More specifically, we can restrict ζ to a subset T of T formed by starting with T and removing one member of each pair ζ0 , −ζ0 . This is justified by the observation that if ζ0 ∈ T , and if (x, y, n1 , . . . , nv , a1 , . . . , ar ) satisfies an instance of (14) with ζ = ζ0 , then (−x, −y, n1 , . . . , nv , a1 , . . . , ar ) satisfies the corresponding instance of (14) with ζ = −ζ0 and all other parameters unchanged. We make one final observation. If l ∈ {1, . . . , v} is an index such that pl has no unramified degree one prime ideals of OK above it, we have πl = 1 and nl = 0. Thus, we can essentially remove such indices from consideration in the algorithm entirely. Specifically, we won’t need to worry about bounding nl at all, and we can remove the terms corresponding to l from the linear forms Λi (i = l) and Λ0 (see Sections 8 and 15 for the definitions of these forms). This will significantly reduce the amount of computation we will need to do. We must still consider the index l in the numerators of c8 and c9 , and when we test 15  candidate solutions of (4). In the implementation of the algorithm, if their are indices l such that pl has no unramified degree one prime ideals dividing it, we proceed as described above. However, to save us some tedious bookkeeping in the exposition, we will assume from now on that, for each i ∈ {1, . . . , v}, there is at least one prime ideal of OK above pi with ramification index and residue degree both equal to 1. In what follows, we assume that we have fixed a particular choice of values for the parameters in (14).  16  6  The S-unit equation From (14) we will deduce a so-called S-unit equation. In doing so, we will eliminate  the variables x, y and set ourselves up to bound the exponents a1 , . . . , ar , n1 , . . . , nv . Let p ∈ {p1 , . . . , pv , ∞}. Denote the roots of g(t) in Qp (where Q∞ = R = C) by θ(1) , . . . , θ(n) . Let i0 , j, k ∈ {1, . . . , n} be distinct indices and consider the three embeddings of K into Qp defined by θ → θ(i0 ) , θ(j) , θ(k) . From the identity θ(i0 ) − θ(j) x − yθ(k) + θ(j) − θ(k) x − yθ(i0 ) + θ(k) − θ(i0 ) x − yθ(j) = 0, we deduce λ=  θ(j) − θ(k) x − yθ(i0 ) θ(i0 ) − θ(j) x − yθ(k) − 1 = θ(i0 ) − θ(k) x − yθ(j) θ(k) − θ(i0 ) x − yθ(j)  (16)  Note λ is being defined by (16). Using (14) to substitute for x − yθ yields the S-unit equation v  λ = δ1  (k)  πi  ni r  (j)  i=1  πi  where δ1 =  (k)  εi  ai  (j)  i=1  εi  θ(i0 ) − θ(j) α(k) ζ (k) , θ(i0 ) − θ(k) α(j) ζ (j)  v  − 1 = δ2  ni r  (j)  i=1  δ2 =  (i0 )  πi  πi  (i0 )  εi  (j)  i=1  ai  ,  (17)  εi  θ(j) − θ(k) α(i0 ) ζ (i0 ) . θ(k) − θ(i0 ) α(j) ζ (j)  Note that δ1 and δ2 are constants (they don’t depend on (x, y, n1 , . . . , nv , a1 , . . . , ar )). We now restrict attention to those p ∈ {p1 , . . . , pv } and study the p-adic valuations of the numbers appearing in (17). Recall that an element z ∈ Cp having ordp (z) = 0 is called a p-adic unit. Lemma 6.1. Let p be a rational prime. If γ ∈ OK and p NK/Q (γ), then γ (h) ∈ Cp is a p-adic unit for every h ∈ {1, . . . , n}.  Proof. In the notation of Section 2, there is i ∈ {1, . . . , m} and j ∈ {1, . . . , ni } such that γ (h) = σij (γ). So, according to (3), ei ordp (γ (h) ) = ordpi (γ). Therefore, if γ (h) is not a p-adic unit, we have that pi divides γ, which implies N (pi ) = pfi divides NK/Q (γ).  17  Let l ∈ {1, . . . , v}. Lemma 6.2. (k)  (i0 )  εi  (a) For every i ∈ {1, . . . , r},  (j)  and  εi  εi  (j)  εi  are pl -adic units.  (i0 )  πi  (b) For every i ∈ {1, . . . , v} with i = l,  (j)  πi  (k)  and  πi  (j)  πi  are pl -adic units.  Proof. Consider any i ∈ {1, . . . , r}. Since εi is a unit in OK , we have NK/Q (εi ) = ±1, and (i0 )  hence εi  (j)  (k)  , εi , εi  NK/Q (πi ) =  are pl -adic units by Lemma 6.1. Now consider an i ∈ {1, . . . , v}. Since  ±N (phi i )  (i0 )  = ±pfi i hi , Lemma 6.1 implies πi  (j)  (k)  , πi , πi  are pl -adic units if i = l.  To conclude it suffices to observe that, since ordpl (x/y) = ordpl (x) − ordpl (y), any ratio of pl -adic units is a pl -adic unit.  From now on we make the following choice for the index i0 . Let gl (t) be the irreducible factor of g(t) in Qpl [t] corresponding to the prime ideal pl . Since pl has ramification index and residual degree equal to 1, deg gl (t) = 1. We choose i0 ∈ {1, . . . , n} so that θ(i0 ) is the root of gl (t). The indices j, k are fixed, but arbitrary. Lemma 6.3. (k)  (a)  πl  (j)  πl  is a pl -adic unit. (i0 )  (b) ordpl  πl  (j)  πl  = hl .  Proof. Consider the factorization of g(t) in Qpl [t]: g(t) = g1 (t) · · · gm (t). Note θ(j) is a root of some gh (t) = gl (t). Let ph be the corresponding prime ideal above pl and eh its ramification index. Then ph = pl and, since (πl ) = phl l , (3) implies (j)  ordpl (πl ) =  1 ordph (πl ) = 0. eh  (k)  An analogous argument gives ordpl (πl ) = 0. On the other hand, (i0 )  ordpl (πl  )=  1 ordpl (πl ) = hl . el  Exploiting the identity ordpl (x/y) = ordpl (x) − ordpl (y) yields the result. 18  The next lemma deals with a special case in which nl can be computed directly. Lemma 6.4. If ordpl (δ1 ) = 0, then nl =  1 (min {ordpl (δ1 ), 0} − ordpl (δ2 )). hl  Proof. Applying Lemmas 6.2 and 6.3 to both expressions for λ in (17) yields ordpl (λ) = min {ordpl (δ1 ), ordpl (1)} and ordpl (λ) = ordpl (δ2 ) + nl hl . In Section 9, we will discuss how to choose the indices j and k in the pl -adic cases. We will work with the indices i0 , j, k in the p = ∞ case in Section 15.  19  7  The p-adic logarithm In this section, we introduce the p-adic logarithm function, extend its domain to include  all p-adic units in Qp , and state several of its important properties. Fix a rational prime p. For z ∈ Cp with ordp (z − 1) > 0, the p-adic logarithm of z is defined to be  ∞  logp z = − i=1  By the  nth  (1 − z)i . i  term test, the series converges precisely in the region where ordp (z − 1) > 0.  Three important properties of the p-adic logarithm are: 1. logp (xy) = logp (x) + logp (y) 2. logp  (z k )  = k logp (z)  whenever ordp (x − 1) > 0 and ordp (y − 1) > 0;  whenever ordp (z − 1) > 0 and k ∈ Z;  3. ordp (logp z) = ordp (z − 1)  whenever ordp (z − 1) > 1/(p − 1).  Proofs of the first and last property can be found in [Ha] (pp. 264-265). The second property follows from the first. We will use the following lemma to extend the definition of the p-adic logarithm to all p-adic units in Qp . Lemma 7.1. Let z be a p-adic unit belonging to a finite extension L of Qp . Let e and f be the ramification index and residue degree of L. (a) There is a positive integer r such that ordp (z r − 1) > 0. (b) If r is the smallest positive integer having ordp (z r − 1) > 0, then r divides pf − 1, and an integer q satisfies ordp (z q − 1) > 0 if and only if it is a multiple of r. (c) If r is a nonzero integer with ordp (z r − 1) > 0, and if k is an integer with pk (p − 1) > e, then k  ordp (z rp − 1) >  1 . p−1  Proof. The residue field of L is the quotient R/m, where R = {z ∈ L : ordp (z ) ≥ 0} and m = {z ∈ L : ordp (z ) > 0}. It is a finite field containing pf elements. Since z is a p-adic unit, the image of z in R/m belongs to the multiplicative group (R/m)× . Let r be the order of the image of z in (R/m)× . So, by definition, r is the smallest positive integer with ordp (z r − 1) > 0, and it follows that r divides pf − 1 and that an integer q satisfies ordp (z q − 1) > 0 if and only if it is a multiple of r. We have now proved (a) and (b). For 20  the proof of (c), let r be any nonzero integer with ordp (z r − 1) > 0 and let k be an integer with pk (p − 1) > e. Write pk −1  z  rpk  r  pk  = (1 + (z − 1))  =1+ l=1  pk k (z r − 1)l + (z r − 1)p . l  (18)  The least positive value that ordp attains on L is 1/e, so we know ordp (z r − 1) ≥ 1/e. pk Applying this inequality and the fact that p divides for l = 1, . . . , pk − 1 in (18) l yields 1 1 pk − 1 pk k ordp (z rp − 1) ≥ min 1 + , . . . , 1 + > , , e e e p−1 where the last inequality follows from definition of k.  For z a p-adic unit in Qp , we define logp z =  1 logp z q , q  where q is an arbitrary nonzero integer such that ordp (z q − 1) > 0. To see that this definition is independent of q, let r be the smallest positive integer with ordp (z r − 1) > 0, note that q/r is an integer, and use the second property of p-adic logarithms above to write 1 1 1 logp z q = logp z r(q/r) = logp z r . q r(q/r) r Choosing q such that ordp (z q −1) > 1/(p−1) helps to speed up and control the convergence of the series defining logp (cf. [Sm] (pp. 28-30) and [Coh2] (pp. 263-265)). It is straightforward to see that Properties 1 and 2 above extend to the case where x, y, z are p-adic units. Combining this fact with Property 3, we obtain: Lemma 7.2. Let z1 , . . . , zm ∈ Qp be p-adic units and let b1 , . . . , bm ∈ Z. If bm ordp (z1b1 · · · zm − 1) >  1 p−1  then bm ordp (b1 logp z1 + . . . + bm logp zm ) = ordp (z1b1 · · · zm − 1).  21  8  A small upper bound for nl in a special case Let l ∈ {1, . . . , v}. In this section, we will identify conditions under which nl can be  bounded by a small explicit constant. We will need to assume that ordpl (δ1 ) = 0. Here (and in Sections 19-23) we find it convenient to use the notation b1 = 1,  b1+i = ni  (i = 1, . . . , v),  b1+v+i = ai  (i = 1, . . . , r).  Put (k)  (k)  α1 = logpl δ1 , α1+i = logpl  πi  (i = 1, . . . , v), α1+v+i = logpl  (j)  πi  Define  εi  (j)  (i = 1, . . . , r).  εi  1+v+r  Λl =  bi αi i=1 (k)  (j)  Let L be a finite extension of Qpl containing δ1 , πi /πi  (k)  (j)  (i = 1, . . . , v), εi /εi  (i =  1, . . . , r). Since finite extensions of p-adic fields are complete, αi ∈ L for i = 1, . . . , 1 + v + r also. Choose φ ∈ Qpl such that L = Qpl (φ) and ordpl (φ) ≥ 0. It is always possible to satisfy the second condition because Qpl (φ ) = Qpl (pm l φ ) for every integer m and every φ ∈ Qpl . Let G(t) be the minimal polynomial of φ over Qpl , and let s be its degree. For i = 1, . . . , 1 + v + r, write s  αih φh−1 ,  αi =  αih ∈ Qpl .  h=1  Then s  Λlh φh−1  Λl =  (19)  h=1  with  v+r+1  Λlh =  bi αih  (h = 1, . . . , s).  i=1  Lemma 8.1. For every h ∈ {1, . . . , s}, we have ordpl (Λlh ) ≥ ordp (Λl ) − ul , where    (20)    wl = ordpl  1≤j<k≤s  1 (φ(k) − φ(j) ) = ordpl (DiscrG(t)). 2  22  Proof. Taking the images of (19) under the conjugation maps φ → φ(h) (h = 1, . . . , s) gives    (1)   Λl1 Λl 1 φ(1) · · · φ(1)s−1  .   .  . .. ..    ..  =  ..  . .   ..  .    (s) Λls Λl 1 φ(s) · · · φ(s)s−1 The s × s matrix φ(h)i−1 above has inverse 1 (φ(k) − φ(j) )   γ11 · · ·  .  ..   1≤j<k≤s  γs1 · · ·   γ1s ..  .  , γss  where each γjk is a polynomial in the entries of φ(h)i−1 having integer coefficients. Since ordpl (φ) ≥ 0 and since ordpl (φ(h) ) = ordpl (φ) for every h, it follows that ordpl (γjk ) ≥ 0 for (i) s i=1 γhi Λl ,  every γjk . Therefore, since Λlh =  we have  (i)  ordpl (Λlh ) ≥ min ordp (Λl ) − ul = ordp (Λl ) − ul 1≤i≤s  for every h ∈ {1, . . . , s}. Lemma 8.2. If nl >  1 − ordpl (δ2 ) , then p−1  1 hl  ordpl (Λl ) = nl hl + ordpl (δ2 ). Proof. Immediate from Lemma 7.2. Lemma 8.3. (a) If ordp (α1 ) < 1 hl  nl ≤ max  min  2≤i≤1+v+r  ordp (αi ), then  1 − ordpl (δ2 ) pl − 1  ,  (b) For all h ∈ {1, . . . , s}, if ordp (α1h ) < nl ≤ max  1 hl  1 − ordpl (δ2 ) pl − 1  ,  1 hl  min  2≤i≤1+v+r  min  2≤i≤1+v+r  ordp (αi ) − ordpl (δ2 )  −1 .  ordp (αih ), then  1 ul + min ordp (αih ) − ordpl (δ2 ) 2≤i≤1+v+r hl  −1 .  Proof. The proof of (a) is analogous to (and simpler than) the proof of (b). Hence we prove only (b). Let h ∈ {1, . . . , s}. First observe that 1+v+r  ordpl (α1h ) = ordpl  Λlh −  bi αih i=2  ≥ min ordpl (Λlh ),  min  2≤i≤1+v+r  ordp (αih ) .  23  Therefore, it suffices to show that ordpl (Λlh ) ≥  min  2≤i≤1+v+r  ordp (αih )  assuming the inequalities nl >  1 hl  1 − ordpl (δ2 ) , pl − 1  nl ≥  1 hl  ul +  min  2≤i≤1+v+r  ordp (αih ) − ordpl (δ2 ) .  By Lemma 8.2, the first inequality implies ordpl (Λl ) = nl hl + ordpl (δ2 ). Combining this with (20) yields ordpl (Λlh ) ≥ nl hl + ordpl (δ2 ) − ul . The desired result now follows from the second assumed inequality.  24  9  Choosing the indices j and k in the pl -adic cases We give here some guidelines for choosing the indices j and k discussed in Section 6 in  the pl -adic cases. Let l ∈ {1, . . . , v} be given. Recall that we require the indices i0 , j, k to be distinct. Also recall that i0 has already been chosen so that θ(i0 ) is the root of a particular linear factor of g(t) in Qpl [t]. We list the guidelines in the order in which they should be followed: 1. If possible, one should choose j, k such that ordpl (δ1 ) = 0 so that Lemma 6.4 applies and yields nl exactly. If this is not possible we know that ordpl (δ1 ) = 0 for every choice of j, k. 2. Try to choose j, k in such a way that Lemma 8.3 can be used to obtain an upper bound for nl . Such an upper bound will be essentially equal to the smallest upper bound that could possibly be obtained through our general procedure for bounding nl (which we will describe in later sections). Moreover, the general procedure is typically much more computationally expensive than the process of searching through the possible values of j, k and checking the hypotheses of Lemma 8.3. 3. If g(t) has three or more linear factors in Qpl [t], choose j, k so that θ(j) , θ(k) are roots of such factors. 4. If g(t) has an irreducible factor in Qpl [t] of degree two, choose j, k so that θ(j) , θ(k) are the roots of such a factor. 5. If g(t) has a nonlinear irreducible factor in Qpl [t] that splits completely in the extension of Qpl that it generates, choose j, k so that θ(j) , θ(k) are roots of such a factor. To check whether g(t) has such a factor, it may be helpful to use the fact that the extension of Qpl generated by an irreducible factor gi (t) of g(t) is isomorphic to the completion of K at the prime ideal above pl to which gi (t) corresponds. 6. Try to choose j, k, so that α1 , . . . , α1+v+r (see Section 8) all belong to Qpl . 7. Try to choose j, k, so that there exists an index i ∈ {2, . . . , 1 + v + r} such that αi =  min  2≤i≤1+v+r  ordpl (αi ) and αi /αi ∈ Qpl for i = 1, . . . , 1 + v + r.  8. Select a nonlinear irreducible factor of g(t) in Qpl [t] of minimal degree and choose j, k so that θ(j) , θ(k) are roots of this polynomial. The case where g(t) has no nonlinear factors in Qpl [t] is handled in Guideline 3. Guidelines 1, 2, 6, and 7 involve searching through all possible choices of j, k until a choice satisfying certain conditions is found. Note that we can restrict these searches to 25  those choices with j < k. This is because going from the choice j = i1 , k = i2 to the choice j = i2 , k = i1 just has the effect of multiplying ordpl (δ1 ) and the αi by −1. If we are successful in choosing j, k such that ordpl (δ1 ) = 0, then we know the value of nl (by Lemma 6.4). If nl is not an integer or if nl < 0, we know the particular instance of (14) we are considering has no solutions. If nl is a nonnegative integer, we can absorb πlnl into α and essentially remove the index l ∈ {1, . . . , v} from consideration in the rest of the algorithm. Specifically, we can skip any work we would do to nl , and we can remove the terms corresponding to l from the linear forms Λi (i = l) and Λ0 (see Sections 8 and 15 for the definitions of these forms). This will save us a substantial amount of computation time. Note that we will still need to consider the index l in the numerators of c8 and c9 , and when we test candidate solutions of (4). We do all of what we have just described in the implementation of the algorithm. However, in order to simplify the exposition, we will assume from now on that ordpl (δ1 ) = 0.  26  10  The general strategy for bounding the ni and the ai Here we outline our strategy for bounding the ai and for bounding those ni to which  lemma 8.3 does not apply. Put N = max {n1 , . . . , nv } ,  A = max {|a1 | , . . . , |ar |} ,  H = max {N, A} .  We will find an explicit upper bound for H. Our strategy depends on the simple observation that if H satisfies an inequality of the form H ≤ a + b log H, for some constants a, b, then H must be bounded (see Lemma 10.1 below). To obtain such an inequality for H, we will bound N and A by linear functions of log H separately. To bound N , we will utilize the theory of linear forms in p-adic logarithms. For A, we will appeal to the theory of linear forms in real/complex logarithms. Lemma 10.1. Let a and b be real numbers with b ≥ e2 . If x ≤ a + b log x, then x < 2(a + b log b).  Proof. Let y be the number defined by x = (1 + y)b log b. Then x ≤ a + b log x = a + b log(1 + y) + b log b + b log log b ≤ a + by + b log b + b log log b By substituting y = x/b log b − 1 in the last expression and rearranging, we find x ≤ b log b +  1 log b (a + b log log b) < b log b + 2 a + b log b , log b − 1 2  where the last inequality assumes that b ≥ e2 .  27  11  A lower bound for linear forms in p-adic logarithms For α an algebraic number, the absolute logarithmic height of α is 1 h(α) = log a N  N  max 1, α(i)  ,  i=1  where a, N , and α(1) , . . . , α(N ) denote, respectively, the leading coefficient, degree, and roots in C of the minimal polynomial of α over Z. Fix a rational prime p. Let α1 , . . . , αm be nonzero algebraic numbers and let L be a number field of degree D containing the αi . Let p be a prime ideal of the ring of integers of L lying above p. Let ep and fp be, respectively, the ramification index and residue degree of p. If p = 2, define d=  D if e2πi/3 ∈ L,  fp if e2πi/3 ∈ L,  f=  2D if e2πi/3 ∈ L,  max {2, fp } if e2πi/3 ∈ L.  If p ≥ 3 and pfp ≡ 3 (mod 4), set d = D,  f = fp .  Finally, if p ≥ 3 and pfp ≡ 1 (mod 4), set d=  D if e2πi/4 ∈ L, 2D if e2πi/4 ∈ L,  f=  fp if e2πi/4 ∈ L or p ≡ 1 (mod 4), max {2, fp } if e2πi/4 ∈ L and p ≡ 3 (mod 4).  Put κ=  2ep log p p−1  and  (κ1 , κ2 , κ3 , κ4 , κ5 , κ6 ) =                       (160, 32, 40, 276, 16, 8)  if p = 2,  (759, 16, 20, 1074, 8, 4)  if p = 3, d ≥ 2,  (537, 16, 20, 532, 8, 4)  if p = 3, d = 1,  (1473, 8τ, 10, 394τ, 8, 4) if p ≥ 5, ep = 1, p ≡ 1 (mod 4),  (1282, 8τ, 10, 366τ, 8, 4)     (1288, 8τ, 10, 396τ, 8, 4)       (319, 16, 20, 402, 8, 4)      (1502, 16, 20, 1372, 8, 4)     (2190, 16, 20, 1890, 8, 4)  if p ≥ 5, ep = 1, p ≡ 3 (mod 4), d ≥ 2, if p ≥ 5, ep = 1, p ≡ 3 (mod 4), d = 1, if p = 5, ep ≥ 2, if p ≥ 7, ep ≥ 2, p ≡ 1(mod4), if p ≥ 7, ep ≥ 2, p ≡ 3(mod4), 28  where τ = (p − 1)/(p − 2). Set  q=  3 if p = 2,  L =  2 if p ≥ 3.   2πi/3 ) if p = 2,    L(e  L(e2πi/4 ) if p ≥ 3 and pfp ≡ 1 (mod 4),    L if p ≥ 3 and pfp ≡ 3 (mod 4).  t  Define u = max t ∈ N : e2πi/q ∈ L , so that q u is the order of the maximal q-subgroup of the group of roots of unity in L . Set c2 =  (m + 1)m+2 dm+2 pf max {1, log d} max log(e4 (m + 1)d), ep , f log p (m − 1)! (f log p)3  c3 = κ1 κm 2  m f log p  m−1 m  max h(αi ), i=1 m  c3 = κ4 (eκ5 )m pκ(m−1)  max h(αi ), i=1  f log p κ3 (m + 4)d  f log p e2 κ6 pκ d  .  Let b1 , . . . , bm ∈ Z, and put bm − 1, λ = α1b1 · · · αm  B = max {|b1 | , . . . , |bm |} .  The following theorem is a consequence of Theorems 1 and 3 of [Yu2] and the lemma in the appendix of [Yu1]. Theorem 11.1. Assume ordp (αi ) = 0 for i = 1, . . . , m. If λ = 0 and B ≥ 3, then ordp (λ) <  c2 min {c3 , c3 } log B. qu  A slightly weaker but computationally easier version of the theorem is obtained upon replacing q u by     3 if p = 2, Q= 4 if p ≥ 3 and pf ≡ 1 (mod 4),    1 if p ≥ 3 and pf ≡ 3 (mod 4).  29  12  A lower bound for linear forms in real/complex logarithms Let α1 , . . . , αm be nonzero algebraic numbers and let L be a number field of degree d  containing the αi . Let L be embedded into C and identify the αi with their images. For i = 1, . . . , m, fix a nonzero determination of log αi . If L is embedded in R, set κ = 1; otherwise, set κ = 2. Put c17 = min  1 κ  1 em 2  m  κ m+3  30  7/2  m  ,2  6m+20  2  max {dh(αi ), |log αi | , 0.16} .  d log(ed) i=1  Let b1 , . . . , bm ∈ Z, and put Λ = b1 log α1 + · · · + bm log αm ,  B = max {|b1 | , . . . , |bm |} .  The following theorem is Corollary 2.3 of [Mat]. Theorem 12.1. If Λ = 0, then |Λ| > exp(−c17 log B − c17 ).  30  13  A bound for nl in terms of log H In this section, we show how the theory of linear forms in p-adic logarithms can be  used to bound each nl by a linear function of log H. Lemma 13.1. For each l ∈ {1, . . . , v}, there is an effectively computable constant c1 (l) such that nl <  c1 (l) 1 log H − ordpl (δ2 ) hl hl  holds whenever H > 2.  Proof. Fix l ∈ {1, . . . , v}. By Lemmas 6.2 and 6.3 applied to (17), we have nl hl = ordpl (λ) − ordpl (δ2 ). So it suffices to find an effectively computable constant c1 (l) such that ordpl (λ) < c1 (l) log H. Let F be the splitting field of g over Q and let σ be an embedding of F into Cpl . Put (k)  α1 = σ −1 (δ1 ),  α1+i = σ −1  (k)  πi  (i = 1, . . . , v),  (j)  πi  α1+v+i = σ −1  εi  (j)  (i = 1, . . . , r).  εi  Since the preimages of θ(i0 ) , θ(j) , θ(k) are easy to determine and since π1 , . . . , πv , ε1 , . . . , εr ∈ Q(θ), it is straightforward to calculate the αi . Set L = Q(α1 , . . . , α1+v+r ). Since the restriction of σ to L is an embedding of L into Cpl , it corresponds to a prime ideal p of L above pl (precisely speaking, it is the equivalence class of embeddings of L into Cpl to which the restriction of σ belongs that corresponds to p, not the embedding itself). So we are in the situation of Section 11 (with p = pl and m = 1 + v + r), and we can compute the constants q u ,c2 ,c3 ,c3 appearing there. Note that these constants depend on the embedding σ chosen only through the ramification index ep and residue degree fp of p. Put c1 (l) =  c2 max {c3 , c3 } . ep q u  By Lemmas 6.2 and 6.3 and since ordpl (δ1 ) = 0, we know the σ(αi ) are pl -adic units. Thereb1 +v+r fore, ordp (αi ) = ep ordpl (σ(αi )) = 0 for all i. Identify λ with its preimage α1b1 · · · α1+v+r −1  in L. By (17), λ = 0. So, by Theorem 11.1, we have ordpl (λ) =  1 c2 max {c3 , c3 } ordp (λ) ≤ log H = c1 (l) log H ep ep q u  provided H > 2. To reduce the work involved in computing c1 (l), we can replace q u above by the constant Q from Section 11. 31  Here is a simple method to choose the embedding σ and determine the prime ideal p of L corresponding to it. Just choose a prime ideal P of F that divides pl and take σ to be the embedding of F into the completion FP . Then p is the unique ideal of L below P: p = P ∩ L. For each l ∈ {1, . . . , v} for which Lemma 8.3 yields upper bounds for nl , let Nl∗ be the smallest such upper bound. Let I be the set of all indices l ∈ {1, . . . , v} for which Lemma 8.3 does not furnish an upper bound for nl . Put c4 = max l∈I  c1 (l) , hl  c4 = max Nl∗ , l∈I /  c4 = max c4 , c4 ,  c5 = max l∈I  −1 ordpl (δ2 ). hl  Lemma 13.2. If H > 2, we have N ≤ c4 log H + c5 .  Proof. Immediate from Lemma 13.1.  Put c6 = 2 max l∈I  −1 ordpl (δ2 ) + max hl  c1 (l) 2 , e log max hl  c1 (l) 2 ,e hl  − 1.  Lemma 13.3. If H = N , we have N ≤ c7 = max 2, c4 , c6 . Proof. We have N = nl for some l ∈ {1, . . . , v}. If l ∈ / I, then N ≤ Nl∗ ≤ c4 , and we are done. If l ∈ I, then, since H = N , Lemma 13.1 says we have N<  c1 (l) 1 log N − ordpl (δ2 ) hl hl  whenever N > 2. It follows from Lemma 10.1 that N <2  −1 ordpl (δ2 ) + max hl  c1 (l) 2 , e log max hl  c1 (l) 2 ,e hl  if N > 2.  32  A bound for A when min x − yθ(i) is large  14  1≤i≤n  In this section, we establish an upper bound for A in terms of log H in the case where min x − yθ(i) is large.  1≤i≤n  Here and in the next section, θ(1) , . . . , θ(n) will denote the roots of g(t) in C, and z (i) will denote the image of z under the embedding θ → θ(i) of K into C. Put c8 = log  |a| p1s1 +t1 · · · pvsv +tv min α(i) ζ (i)  ,  c9 = log  1≤i≤n  ph1 1 · · · phv v (i)  min π1 · · · πv(i)  ,  1≤i≤n  (i)  c9 = log max π1 · · · πv(i) .  c8 = log max α(i) ζ (i) ,  1≤i≤n  1≤i≤n  For any r × r matrix U = (uij ), the row-norm of U is r  |uij | .  U = max  1≤i≤r  j=1  For each set κ = {k1 , . . . , kr } ⊆ {1, . . . , s + t} of indices with k1 < · · · < kr , define (ki )  Uκ = (uij ) = log εj  .  Note each Uκ is invertible because its determinant is a multiple of the regulator of K. Set c10 =  1 , min Uκ−1 κ  and let c11 be any number satisfying 0 < c11 <  c10 . n−1  So we have c10 − c11 > c10 − (n − 1)c11 > 0. Lemma 14.1. If min x − yθ(i) > e−c11 A , we have 1≤i≤n  A<  c8 + c9 N c10 − (n − 1)c11  or  A<  c8 + c9 N . c10 − c11  Proof. Let κ0 = {k1 , . . . , kr } be an index set such that Uκ−1 = min Uκ−1 = 0 κ  1 . c10 33  Put ε = εa11 . . . εar r . Since r  log ε  (ki )  (ki )  =  (i = 1, . . . , r),  aj log εj j=1  we have  r  uij log ε(kj )  ai =  (i = 1, . . . , r),  j=1  where (uij ) =  Uκ−1 . 0  Choose k ∈ κ0 such that log ε(k) = max log ε(i) . k∈κ0  Then r  r  uij log ε(kj ) ≤ log ε(k)  A = max |ai | ≤ max 1≤i≤r  1≤i≤r  j=1  uij = log ε(k)  max  1≤i≤r  Uκ−1 . 0  j=1  It follows that we have either ε(k) ≤ e−c10 A or ε(k) ≥ ec10 A . According to (14), ε(k) =  x − yθ(k) (k) n1  α(k) ζ (k) π1  (k) nv  .  · · · πv  So ε(k) ≤ e−c10 A implies e−c10 A ≥ >  x − yθ(k) (k) n1  α(k) ζ (k) π1  (k) nv  · · · πv  e−c11 A (i)  max α(i) ζ (i) max π1 · · · πv(i)  N  1≤i≤n  1≤i≤n  = exp −c11 A − c8 − c9 N , whence A<  c8 + c9 N . c10 − c11  By (6) and (15), x − yθ(k) = |a| pz11 · · · pzvv  x − yθ(k)  −1  < |a| pn1 1 h1 +s1 +t1 · · · pvnv hv +sv +tv e(n−1)c11 .  i=k  34  So ε(k) ≥ ec10 A implies x − yθ(k)  ec10 A ≤ <  <  (k) n1  α(k) ζ (k) π1  (k) nv  · · · πv  |a| ps11 +t1 · · · psvv +tv pn1 1 h1 · · · pvnv hv · · e(n−1)c11 A (k) n1 (k) nv α(k) ζ (k) π1 · · · πv N  |a| ps11 +t1 · · · psvv +tv  ph1 1 · · · phv v  (n−1)c11 A ·  ·e  (i) (i) (i) (i) min α ζ min π1 · · · πv 1≤i≤n  1≤i≤n  = exp c8 + c9 N + (n − 1)c11 A , from which we deduce A<  c8 + c9 N . c10 − (n − 1)c11  Put c8 + c5 c9 , c10 − (n − 1)c11 c + c5 c9 , = 8 c10 − c11  c12 =  c13 = max  c12  c13 = max  c4 c9 , e2 , c10 − (n − 1)c11 c4 c9 , e2 c10 − c11  Lemma 14.2. If min x − yθ(i) > e−c11 A and H = A, then 1≤i≤n  H ≤ c14 , where c14 = max  2(c12 + c13 log c13 ) − 1, 2(c12 + c13 log c13 ) − 1, 2 .  Proof. Assume H > 2. Then Lemmas 13.2 and 14.1 imply that we have either A<  c8 + c5 c9 c4 c9 + log H c10 − (n − 1)c11 c10 − (n − 1)c11  or c8 + c5 c9 c4 c9 + log H. c10 − c11 c10 − c11 Since H = A, Lemma 10.1 and the first inequality imply H < 2(c12 + c13 log c13 ), while A<  Lemma 10.1 and the second inequality yield H < 2(c12 + c13 log c13 ). Note that (except for the requirement 0 < c11 < c10 /(n − 1)) c11 is a free parameter that we will use later to optimize bounds that depend on it. 35  A bound for A when min x − yθ(i) is small  15  1≤i≤n  In Section 14, we established an upper bound for A in terms of log H in the case min x − yθ(i) > e−c11 A . In this section, we will prove an analogous an estimate when  1≤i≤n  min x − yθ(i) ≤ e−c11 A . Unless s = 0, we will need to use the theory of linear forms in  1≤i≤n  real/complex logarithms. Put c15     max =   0  −  1 log min Im θ(j) s+1≤j≤s+t c11  ,0  if t > 0, if t = 0.  Lemma 15.1. If t > 0, i ∈ {s + 1, . . . , s + 2t}, and x − yθ(i) ≤ e−c11 A , then A ≤ c15 . Proof. If y = 0, we have x = ±1 (since (x, y) = 1), and it follows from (14) that A = 0. If |y| ≥ 1, then e−c11 A ≥ x − yθ(i) ≥ Im θ(i) ≥  min  s+1≤j≤s+t  Im θ(j) ,  whence A ≤ c15 .  The following lemma takes cares of the s = 0 case. Lemma 15.2. If min x − yθ(i) ≤ e−c11 A and s = 0, then 1≤i≤n  A ≤ c15 .  Proof. Immediate from Lemma 15.1  For the s > 0 case, we will work with the indices i0 , j, k ∈ {1, . . . , n} from the p = ∞ case of Section 6. We order the roots of g(t) in C so that θ(1) , . . . , θ(s) ∈ R,  θ(s+1) = θ(s+t+1) , . . . , θ(s+t) = θ(s+t2t) ∈ C \ R,  where n = s+2t. Our method for computing an upper bound for A requires that we choose i0 to be an index satisfying x − yθ(i0 ) = min x − yθ(i) . As this condition depends on 1≤i≤n  (x, y), we cannot make a definite choice for i0 without actually solving (14). We can 36  overcome this difficulty by computing a bound for A for each of the cases i0 = 1, . . . , n and then taking the largest of the bounds obtained. In fact, since Lemma 15.1 yields an upper bound for A when i0 ∈ {s + 1, . . . , s + 2t}, t > 0, we only need to concern ourselves with the cases i0 = 1, . . . , s. For each i0 ∈ {1, . . . , s}, we define numbers j = j(i0 ), k = k(i0 ), Λ0 = Λ0 (i0 ), c16 = c16 (i0 ), c17 = c17 (i0 ), c18 = c18 (i0 ), and (in the s = 1, 2 case) a0 = a0 (i0 ) as follows. We separate the two cases s ≥ 3 and s = 1, 2. These are called, respectively, the real case and the complex case. In both cases, j, k will be indices in {1, . . . , n} such that i0 = j = k = i0 . If s ≥ 3, we stipulate that j, k ∈ {1, . . . , s} in order to have θ(i0 ) , θ(j) , θ(k) ∈ R. If s = 1, 2, we require that j ∈ {s + 1, . . . , s + t} and k = j + t so that θ(j) = θ(k) . Subject to these restrictions, we fix a choice for j, k that minimizes the number c16 =  θ(j) − θ(k) . θ(k) − θ(i0 )  2 (i ) 0 θ − θ(j)  In the real case, put v  r  (k)  Λ0 = log(|1 + λ|) = log δ1 +  ni log i=1 (k)  (j)  By the choice of j, k, the numbers 1 + λ, δ1 , πi /πi  πi  (j)  +  πi  (k)  ai log i=1  εi  (j)  .  εi  (k)  (j)  (i = 1, . . . , v), εi /εi  (i = 1, . . . , r)  are all real, so taking their absolute values just multiplies them by ±1. Let F be the splitting field of g over Q and let σ be an embedding of F into C. Put (k)  α1 = σ −1 (|δ1 |),  α1+i = σ −1  πi  (j)  (i = 1, . . . , v),  πi  (k)  α1+v+i = σ  −1  εi  (j)  (i = 1, . . . , r).  εi  As with the αi from the proof of Lemma 13.1, the αi here are straightforward to calculate. Set L = Q(α1 , . . . , α1+v+r ). We are now in the situation of Section 12 (with L embedded into C via σ and m = 1 + v + r), and we can compute the constant c17 appearing there. Note that the value of c17 depends on the embedding σ chosen only through the number κ. Note also that Λ0 is equal to Λ from Section 12 (with the obvious identifications for the bi ). So, according to Theorem 12.1, |Λ0 | > exp(−c17 log H − c17 )  (21)  if Λ0 = 0. 37  In the complex case, define 1 Λ0 = Log(1 + λ). i Here Log(z) denotes the principal branch of the logarithm of z, so Re(Log(z)) = log |z| and Im(Log(z)) ∈ (−π, π]. We have iΛ0 = Log(1 + λ) = Log  θ(i0 ) − θ(j) x − yθ(k) θ(i0 ) − θ(k) x − yθ(j)  v  = Log (δ1 ) +  ni Log i=1  = Log  r  (k)  πi  (k)  +  (j)  πi  ai Log i=1 v  θ(i0 ) − θ(j) α(k) ζ (k) θ(i0 ) − θ(k) α(j) ζ (j)  +  ni Log i=1  εi  (j)  εi  + 2πia0 r  (k)  πi  (j)  +  πi  (k)  ai Log i=1  εi  (j)  εi  + 2πia0  for some integer a0 . As θ(i0 ) ∈ R and θ(j) = θ(k) , each logarithm above has real part equal to zero and, therefore, modulus less than or equal to π. So by the triangle inequality v  2π |a0 | ≤ 2π +  r  ai π ≤ (2 + (v + r)H)π ≤ (1 + v + r)Hπ  ni π + i=1  (22)  i=1  for H ≥ 2. Since πi = Log(−1), iΛ0 is a linear form in logarithms of 2 + v + r complex numbers. So, as in the real case, we can compute the constant c17 from Section 12, and we have |Λ0 | > exp(−c17 log(max {H, 2 |a0 |}) − c17 ) ≥ exp(−c17 log((1 + v + r)H) − c17 )  (23)  if Λ0 = 0 by Theorem 12.1 and (22). Finally, put c18 =  if s ≥ 3,  log(2(log 2)c16 ) + c17  log(4 sin−1 (1/4)c16 ) + c17 (1 + log(1 + v + r)) if s = 1, 2.  Lemma 15.3. Assume min x − yθ(i) ≤ e−c11 A , H ≥ 2, and s > 0. For each i0 ∈ 1≤i≤n  {1, . . . , s}, if x −  yθ(i0 )  = min x − yθ(i) and 1≤i≤n  A ≥ max  log(2c16 (i0 )) ,1 , c11  then A<  1 (c18 (i0 ) + c17 (i0 ) log H). c11  For the proof of Lemma 15.3, we will need the following two simple lemmas. 38  Lemma 15.4. Let z ∈ C and 0 < c < 1. If |ez − 1| ≤ c, then |z| ≤  − log(1 − c) z |e − 1|. c  Proof. ∞ z  |z| = |Log(e )| = i=1  Lemma 15.5. Let −  (−1)i−1 (ez − 1)i ≤ |ez − 1| i  ∞ i=1  − log(1 − c) z ci−1 = |e − 1|. i c  π π < z ≤ and 0 < c < 1. If | sin z| ≤ c, then 2 2 |z| ≤  sin−1 (c) | sin z|. c  Proof. The inequality −c ≤ sin z ≤ c implies − sin−1 (c) ≤ z ≤ sin−1 (c). So, since the function u → u/ sin u has even symmetry and is increasing on (0, sin−1 (c)], it follows that sin−1 (c) sin−1 (c) |z| ≤ = | sin z| c sin(sin−1 (c)) when z = 0. Proof of Lemma 15.3. Let i0 ∈ {1, . . . , s}, and assume x − yθ(i0 ) = min |x − yθ(i) | and 1≤i≤n  A ≥ max { log(2c16 )/c11 , 1}. Since A > 0, we have |y| ≥ 1 (by the first sentence in the proof of Lemma 15.1). Therefore, θ(i0 ) − θ(j) ≤ y(θ(i0 ) − θ(j) ) = (x − yθ(i0 ) ) − (x − yθ(j) ) ≤ 2 x − yθ(j) . So by (16) |λ| =  x − yθ(i0 ) θ(j) − θ(k) · ≤ c16 x − yθ(i0 ) ≤ c16 e−c11 A . x − yθ(j) θ(k) − θ(i0 )  Since A ≥ log(2c16 )/c11 , it follows that |λ| ≤ 12 . By (16), we also have λ = 0. In the real case, λ ∈ R. So, since 0 < |λ| ≤ eΛ0  − 1 = |λ| ≤  1 2  |Λ0 | ≤  1 2,  we have 0 < 1 + λ < 1. Then  and, therefore, by Lemma 15.4 (with z = Λ0 and c = 21 ), − log 1 − 1 2  1 2  eΛ0 − 1 = 2(log 2) |λ| ≤ 2(log 2)c16 e−c11 A .  39  Additionally, since 0 < 1 + λ < 1, we have Λ0 = 0, and so |Λ0 | > exp(−c17 log H − c17 ). by (21). Combining these bounds for |Λ0 | yields c11 A ≤ log(2(log 2)c16 ) + c17 + c17 log H = c18 + c17 log H. In the complex case, we have Λ0 ∈ (−π, π] and 2 sin Applying Lemma 15.5 with z = 21 Λ0 and c = |Λ0 | ≤ 2 ·  sin−1 (1/4) sin sin−1 (1/4)  sin  1 Λ0 2  1 4  1 2 Λ0  = eiΛ0 − 1 = |λ| ≤ 12 .  then yields  = 4 sin−1 (1/4) |λ| ≤ 4 sin−1 (1/4)c16 e−c11 A .  On the other hand, since λ = 0, we have Λ0 = 0. Thus, by (23), |Λ0 | > exp(−c17 log((1 + v + r)H) − c17 ). Putting the upper and lower bounds for |Λ0 | together leads to c11 A ≤ log(2(log 2)c16 ) + c17 + c17 log H = c18 + c17 log H.  Put log(2c16 (i0 )) − 1, c11 c18 (i0 ) c17 (i0 ) 2 = 2 max + max , e log max 1≤i0 ≤s c11 c11  c19 = max  1≤i0 ≤s  c20  c17 (i0 ) 2 ,e c11  − 1.  Lemma 15.6. If min x − yθ(i) ≤ e−c11 A , s > 0, and H = A, then 1≤i≤n  A ≤ c21 = max {c15 , c19 , c20 , 1} Proof. Assume A > max {c15 , c19 , 1}, and let i0 ∈ {1, . . . , n} be an index such that |x − yθ(i0 ) | = min |x − yθ(i) |. By Lemma 15.1, we know that i0 ∈ {1, . . . , s}. So, since 1≤i≤n  H = A ≥ max { log(2c16 (i0 ))/c11 , 2}, Lemma 15.3 implies A<  c18 (i0 ) c17 (i0 ) + log A. c11 c11  It then follows from Lemma 10.1 that A<2  c18 (i0 ) + max c11  c17 (i0 ) 2 , e log max c11  c17 (i0 ) 2 ,e c11  ,  whence A ≤ c20 .  40  16  A bound for H By combining Lemma 13.3, Lemma 14.2, and (depending on the value of s) either  Lemma 15.2 or Lemma 15.6, we obtain the following explicit and unconditional upper bound on H. Theorem 16.1. H ≤ c22 =  max {c7 , c14 , c15 } if s = 0 max {c7 , c14 , c21 } if s > 0  The constants c14 , c15 , c21 depend on the parameter c11 , which we are free to choose so that the upper bound c21 is optimized (subject to the condition 0 < c11 < c10 /(n − 1)). In practice, the constants c1 (l), c4 , and c17 , which arise directly from the estimates for linear forms in logarithms, will be very large. The same goes for all constants depending on c1 (l), c4 , and c17 . All the other constants will be comparatively small. If s = 0, c22 will therefore be essentially of the size max c4 ,  c4 c10 − (n − 1)c11  ,  and an optimal choice for c11 will be near (c10 − 1)/(n − 1). In case s > 0, c22 will be of the size max c4 , So if c4  c4 , c17 /c11 . c10 − (n − 1)c11  c17 , an optimal choice for c11 will be roughly c17 /c4 . If c4  c17 , an optimal  choice for c11 will be of the size c10 /(n − 1). And if c4 ≈ c17 , the size of the optimal c11 will be somewhere between the size of c17 /c4 and the size of c10 /(n − 1). Corollary 16.2. For each l ∈ {1, . . . , v}, nl ≤ min c22 , max  1 c1 (l) log c22 − ordpl (δ2 ) − 1, 2 hl hl  Proof. If nl > 2, then H > 2, so Lemma 13.1 and Theorem 16.1 imply nl ≤  c1 (l) 1 c1 (l) 1 log H − ordpl (δ2 ) − 1 ≤ log c22 − ordpl (δ2 ) − 1. hl hl hl hl  Evidently, one should use Corollary 16.2 rather than Theorem 16.1 to bound nl when l ∈ I. 41  17  The reduction strategy The upper bounds on A = max {|a1 | , . . . , |ar |} and the nl furnished by Theorem 16.1  and its corollary are expected to be very large. Indeed, bounds of the size 1040 are typical even when the degree n and the number v of primes are both small. Enumeration of the solutions of (14) by a naive search at this stage would be virtually impossible. In order to make a search feasible, we need to reduce the upper bounds on A and the nl considerably. In this section, we outline our strategy for doing just that. Our strategy has several steps, and the best known upper bounds on A and the nl will change from step to step. In each step, Nl will denote the current best upper bound for nl (l = 1, . . . , v), and A0 will denote the current best upper bound for A. We will also use H0 to denote the best known upper bound for H = max {n1 , . . . , nv , |a1 |, . . . , |ar |} in a given step. So H0 = max {N1 , . . . , Nv , A0 }. We will use the bi notation (see Section 8) frequently in Sections 19-23. It will therefore be convenient to let Bi stand for the current best upper bound for |bi | (i = 1, . . . , 1 + v + r). We will never bound the ai individually, so we will always have B1 = 1,  B1+i = Ni  (i = 1, . . . , v),  B1+v+i = A0  (i = 1, . . . , r).  As we remarked in Section 9, for each index l ∈ {1, . . . , v} for which Lemma 8.3 gives an upper bound for nl , there is no need to reduce that upper bound further. Recall that I denotes the set of all indices l in {1, . . . , v} to which Lemma 8.3 does not apply. There are four types of reduction procedures involved in the strategy. We refer to them as ‘basic p-adic reduction’, ‘basic real reduction’, ‘refined p-adic reduction’, and ‘refined real reduction’. Now for the strategy itself. First, for each l ∈ I in turn, we perform the basic pl -adic reduction procedure to (ideally) reduce Nl to the size of log H0 . Next we perform the basic real reduction procedure to reduce A0 . If everything goes as planned, the new A0 will be the size of log H0 also. We repeat the steps above (pi -adics, then real) until the bounds stop improving. Then we move onto the refined reduction procedures. We start by performing the refined pl -adic reduction procedure for each l ∈ I to reduce the bounds Nl . Then we perform the refined real reduction procedure to improve A0 . As with the basic procedures, we expect a reduction to something like log H0 in each step, and we repeat until we stop making progress with the bounds.  42  18  Lattice basis reduction The four types of reduction procedures involved in our reduction strategy all rely on  Diophantine approximation techniques involving lattice basis reduction. In this section, we present those aspects of the theory of lattice basis reduction that we will need. An n-dimensional lattice is a subset of Rn of the form n  xi ci : xi ∈ Z ,  Γ= i=1  where c1 , . . . , cn are vectors forming a basis for Rn . We say that the vectors c1 , . . . , cn form a basis for Γ, or that they generate Γ. The following basic fact about lattice bases will be useful: If A and B are invertible n × n real matrices, then the lattice generated by the columns of A is equal to the lattice generated by the columns of B if and only if there is a unimodular integer matrix U such that AU = B. Let Γ be a lattice with basis c1 , . . . , cn . Define vectors c∗i (i = 1, . . . , n) and real numbers µij (1 ≤ j < i ≤ n) inductively by i−1  c∗i = ci −  µij c∗j ,  µij =  j=1  ci , c∗j c∗j , c∗j  (this is just the Gram-Schmidt process). The basis c1 , . . . , cn is called LLL-reduced if |µij | ≤ 3 ∗ c 4 i−1  2  1 2  for 1 ≤ j < i ≤ n,  ≤ c∗i + µii−1 c∗i−1  2  for 1 < i ≤ n.  These properties imply that an LLL-reduced basis is approximately orthogonal and that, generically, its constituent vectors are of roughly the same length. Every n-dimensional lattice has an LLL-reduced basis and such a basis can be computed very quickly using the so-called LLL algorithm (see [LLL]). The LLL algorithm takes as input an arbitrary basis for a lattice and outputs an LLL-reduced basis for the lattice. The algorithm is typically modified to additionally output a unimodular integer matrix U such that B = AU , where A is the matrix whose column-vectors are the input basis and B is the matrix whose column-vectors are the LLL-reduced output basis. Several versions of this algorithm are implemented in Magma, including de Weger’s exact integer version (see [dW1] (Section 3.5), [Sm] (Section V.4), or [Coh1] (Section 2.6.3)) and Nguyen and Stehl´e’s exact floating 43  point version (see [NS], [St]). Note that Nguyen and Stehl´e’s algorithm requires a slight modification of the notion of LLL-reduced given above. For Γ an n-dimension lattice and y a vector in Rn , we define min |x − y| .  l(Γ, y) =  x∈Γ\{y}  The most important property of an LLL-reduced basis for us is the following lemma. Lemma 18.1. Let Γ be a lattice with LLL-reduced basis c1 , . . . , cn and let y be a vector in Rn . (a) If y = 0, then l(Γ, y) ≥ 2−(n−1)/2 |c1 |. (b) Assume y = s1 c1 + · · · sn cn , where s1 , . . . , sn ∈ R with not all si ∈ Z. Put J = {j ∈ {1, . . . , n} : sj ∈ / Z}. For each j ∈ J, set δ(j) = maxi>j si |ci | if j < n, and set δ(j) = 0 if j = n. Here · denotes the distance to the nearest integer. We have l(Γ, y) ≥ max 2−(n−1)/2 sj |c1 | − (n − j)δ(j) . j∈J  Lemma 18.1(a) is Proposition 1.11 in [LLL]; proofs can be found in [LLL], [dW1] (Section 3.4), or [Sm] (Section V.3). Lemma 18.1(b) is a combination of Lemmas 3.5 and 3.6 in [dW1]. Note that the assumption in Lemma 18.1(b) is equivalent to y ∈ / Γ. In the refined reduction procedures, we will need to compute all the vectors in a given lattice which have norm less than or equal to some constant. This can be done efficiently using an algorithm of Fincke-Pohst (cf. [FP], [Coh1]). A version of this algorithm with some improvements due to Stehl´e is implemented in Magma. A function to estimate the computational cost of this algorithm is also available.  44  19  Preliminaries for the pl -adic reduction procedure In this section, we set some notation and give some preliminaries for the pl -adic reduc-  tion procedures. We will refer to the notation of Section 8. Consider a fixed l ∈ I. We have ordpl (α1 ) ≥  min  2≤i≤1+v+r  ordp (α1h ) ≥  ordpl (αi ),  min  2≤i≤1+v+r  ordp (αih )  Let I be the set of all indices i ∈ {2, . . . , 1 + v + r} for which αi =  (h = 1, . . . , s). (24) min  2≤i≤1+v+r  ordpl (αi ).  We distinguish two cases, which we call the special case and the general case. The special case is when there is some index i ∈ I such that αi /αi ∈ Qpl for i = 1, . . . , 1 + v + r. The general case is when there is no such index. In the special case, we let ˆi be an arbitrary index in I for which αi /αˆi ∈ Qpl for i = 1, . . . , 1 + v + r. We further define βi = −  αi αˆi  (i = 1, . . . , 1 + v + r),  and Λl =  1 Λl = αˆi  1+v+r  bi (−βi ). i=1  In the general case, we first fix an h ∈ {1, . . . , s} arbitrarily. Then we let ˆi be an index in {2, . . . , 1 + v + r} such that ordp (αˆih ) =  min  2≤i≤1+v+r  ordp (αih ),  and define βi = −  αih αˆih  (i = 1, . . . , 1 + v + r),  and Λl =  1 Λlh = αˆih  1+v+r  bi (−βi ). i=1  Note that in both cases we have βi ∈ Zpl for i = 1, . . . , 1 + v + r. This is clear for i = 2, . . . , 1 + v + r. For i = 1, it follows from (24).  45  Lemma 19.1. Suppose nl >  1 hl  1 − ordpl (δ2 ) . pl − 1  In the special case, we have ordpl (Λl ) = nl hl + dl with dl = ordpl (δ2 ) − ordp (αˆi ). In the general case, we have ordpl (Λl ) ≥ nl hl + dl with dl = ordpl (δ2 ) − ul − ordp (αˆih ). Proof. Immediate from Lemmas 8.1 and 8.2, and the definition of Λl . Now we state several relatively-easy-to-check conditions that each imply that we are in the special case. In fact, each condition implies that we have αi1 /αi2 ∈ Qpl for every i1 , i2 ∈ {1, . . . , 1 + v + r}. Note that these conditions correspond to the guidelines 3-6 for choosing j and k in Section 9. (a) α1 , . . . , α1+v+r belong to Qpl . (b) g(t) has three or more linear factors in Qpl [t], and θ(i0 ) , θ(j) , θ(k) are roots of such polynomials. (c) g(t) has an irreducible factor in Qpl [t] of degree two, and θ(j) , θ(k) are the roots of this factor. (d) g(t) has a nonlinear irreducible factor in Qpl [t] that splits completely in the extension of Qpl that it generates, and θ(j) , θ(k) are roots of this factor. It is obvious that (a) implies αi1 /αi2 ∈ Qpl for every i1 , i2 ∈ {1, . . . , 1 + v + r}. If (b) (k)  (j)  holds, then δ1 , πi /πi  (k)  (j)  (i = 1, . . . , v), εi /εi  (i = 1, . . . , r) all belong to Qpl , which,  since Qpl is complete, implies (a). It is clear that (c) implies (d). We claim that (d) implies αi1 /αi2 ∈ Qpl for every i1 , i2 ∈ {1, . . . , 1 + v + r}. To see that the claim holds, assume (d), let L be the extension of Qpl generated by the factor of g(t) in question, and consider  46  any α, β ∈ L. The automorphism of L that maps θ(j) to θ(k) multiplies the logarithms logpl α(k) /α(j) and logpl β (k) /β (j) by −1 and hence fixes the quotient logpl α(k) /α(j) logpl β (k) /β (j)  .  (25)  Therefore, since L is Galois, this quotient belongs to Qpl . Since αi1 /αi2 is of the form (25) for every i1 , i2 ∈ {1, . . . , 1 + v + r}, the claim is proved. When performing the computations associated with the refined reduction procedures (Section 22 and Section 23), we will encounter the situation where we have computed α1 , . . . , α1+v+r and β1 , . . . , β1+v+r , we have explicit integers b1 , . . . , b1+v+r , and we wish to verify the conclusions of Lemma 8.2 and Lemma 19.1. Moreover, we will encounter this situation a large number of times, so it is desirable to perform the verifications as efficiently as possible. In the special case, the conclusions of Lemmas 8.2 and 19.1 are equivalent. Thus we can save on computation time by checking the conclusion for just one of the two lemmas. This explains why we bother distinguishing the special case from the general case. In both the special and general cases, verifying the conclusion of Lemma 8.2 requires us to compute Λl , which typically involves working in a nontrivial extension of Qpl . Verifying the conclusion of Lemma 19.1 necessitates computing Λl , which only involves calculations in Zpl . Hence, in the special case, it is preferable to skip checking Lemma 8.2 in favour of Lemma 19.1. In the general case, while we cannot simply skip checking one of the two lemmas, we can discuss which lemma we should check first. There are two competing factors to consider. The first factor is that the situation where we will need to verify the conclusions of the two lemmas will be such that if we find that the conclusion of one of the two lemmas does not hold, then we don’t need to check the conclusion of the other lemma. So, since the conclusion of Lemma 8.2 implies the conclusion of Lemma 19.1, and not conversely, we have reason to favour checking Lemma 8.2 before Lemma 19.1. The second factor is that, as we noted above, it is computationally cheaper to check the conclusion of Lemma 19.1 than to check the conclusion of 8.2. This second factor suggests that we should check Lemma 19.1 before Lemma 8.2. In our experience, we have found it slightly preferable (from a speed perspective) to test Lemma 19.1 before Lemma 8.2, indicating that the second factor may more important than the first. However, it is not clear which order of testing the lemmas (if any) is optimal in general.  47  20  Basic pl -adic reduction Here we describe the basic pl -adic reduction procedure. Fix l ∈ I. We start with some preliminaries. Let m, W2 , . . . , W1+v+r denote positive  integers. These are parameters that we will need to balance in order to obtain a good reduction of the upper bound for nl . We will discuss how to choose them later in this section. For each x ∈ Zpl , x{m} will stand for the unique rational integer in [0, pm l − 1] such that ordpl (x − x{m} ) ≥ m (i.e., x ≡ x{m} (mod pm l )). Let Γm be the (v + r)-dimensional lattice generated by the column-vectors of the matrix  W2  ..  .  0   Wˆi−1   Am =  0 Wˆi+1   ..  .     {m} {m} {m} Wˆi β2 · · · Wˆi βˆi−1 Wˆi βˆi+1 · · · Put λ= and  1 pm     W1+v+r {m}  Wˆi β1+v+r Wˆi pm l         .         1+v+r {m}  bi −βi i=1    0 .. .        y=  ∈ Zv+r .  0    {m} Wˆi β1 Evidently, we must compute the βi to p-adic precision at least m in order to avoid errors here. We observe that y ∈ Γm if and only if y = 0. To see that this is true, note that y ∈ Γm means there are integers z1 , . . . , zv+r such that y = Am [z1 , . . . , zv+r ]T . The last {m}  equation forces z1 = · · · = zv+r−1 = 0 and −β1  {m}  = zv+r pm l . Since β1  ∈ [0, pm l − 1], we  must then have zv+r = 0 also. Hence y = 0. Our observation means that Lemma 18.1 is available to estimate l(Γm , y). Put  1+v+r  Wi2 Bi2 .  Q= i=2  48  Lemma 20.1. If l(Γm , y) > Q1/2 , then 1 − ordpl (δ2 ) pl − 1  1 hl  nl ≤ max  ,  1 (m − dl ) − 1, 0 hl  Proof. We prove the contrapositive. Assume nl > (1/hl ) (1/(pl − 1) − ordpl (δ2 )), nl ≥ (1/hl )(m − dl ), and nl > 0. Consider the vector     b2 W2 b2     ..  ..     .    .      b     ˆi−1   Wˆi−1 bˆi−1         x = Am   bˆi+1  =  Wˆi+1 bˆi+1  + y.  .    ..  ..    .         b1+v+r  W1+v+r b1+v+r      λ Wˆi bˆi By Lemma 19.1, 1+v+r  ordpl  = ordpl (Λl ) ≥ nl hl + dl ≥ m.  bi (−βi ) i=1  {m}  Since ordpl (βi  − βi ) ≥ m for i = 1, . . . , 1 + v + r, it follows that 1+v+r {m}  ordpl  bi (−βi  )  ≥ m,  i=1  which means λ ∈ Z. Hence x ∈ Γm . Since bl+1 = nl > 0, we cannot have x = y. Therefore, 1+v+r  1+v+r 2  2  Wi2 b2i  l(Γm , y) ≤ |x − y| = i=2  Wi2 Bi2 = Q.  ≤ i=2  The reduction procedure works as follows. Taking Am as input, we first compute an LLL-reduced basis for Γm . Then we find a lower bound for l(Γm , y) using Lemma 18.1. If the lower bound is greater than Q1/2 , Lemma 20.1 gives a new upper bound for nl . If not, we should increase m and try the procedure again. In such a situation, we can take advantage of the computations already done by starting with a partially reduced basis for the new lattice Γm (m > m) rather than the basis given by Am . We will have computed, for a certain m, a matrix Bm whose columns form a LLL-reduced basis for Γm , and a 49  unimodular integer matrix Um such that Am Um = Bm . We want to compute a reduced basis for Γm . Instead of using Am as the input basis for the LLL algorithm, we can use the partially reduced basis for Γm given by the columns of Am Um . If we find that several increases of m have failed to yield a new upper bound for nl and that the value of m has become significantly larger than it was initially, then we should move on to the next l ∈ I (or onto the real reduction procedure if there is no next l ∈ I). Now we discuss how to choose m and the so-called weights Wi . To optimize the bound for nl produced by the reduction procedure, one should take m as small as possible while ensuring that the lower bound for l(Γm , y) furnished by Lemma 18.1 is large enough that the hypothesis of Lemma 20.1 is satisfied. We will use a heuristic argument to determine an approximately optimal choice for m. The main step in the argument is finding an inequality involving m and the Wi that is roughly equivalent to the hypothesis of Lemma 20.1. Let c1 , . . . , cv+r denote any LLL-reduced basis for Γm and let Bm be the matrix having c1 , . . . , cv+r as its column-vectors. Since the columns of both Am and Bm are bases for Γm , there is a unimodular matrix Um such that Am Um = Bm . Therefore, |detAm | = |detBm |. On the one hand, we see that |detAm | = pm l  1+v+r i=2  Wi . On the  other hand, since c1 , . . . , cv+r are nearly orthogonal, we have |detBm | ≈ |c1 | · · · |cv+r |. Since we can expect that the ci are all of approximately the same length, we thus have 1+v+r i=2 2−(v+r)/2 (pm l  |c1 |v+r ≈ pm l the size  Wi . The lower bound for l(Γm , y) from Lemma 18.1 is therefore of 1+v+r i=2  Wi )1/(v+r) . Thus the hypothesis of Lemma 20.1 is essentially  the inequality 1/(v+r)  1+v+r  2  −(v+r)/2  pm l  Wi  1/2  1+v+r  Wi2 Bi2  >  i=2  ,  i=2  which is equivalent to   1+v+r     2v+r Wi2 Bi2    v+r   i=2 m> log  . 1/(v+r)  1+v+r  2 log p   Wi2 i=2  Hence the optimal value of m will be approximately   1+v+r     2v+r Wi2 Bi2    v+r   i=2 m0 = log  . 1/(v+r)   1+v+r 2 log p   Wi2 i=2  50  We are free to choose the weights Wi to minimize this expression, but this is not easy to do in general. Instead, we consider two simple candidate choices for the weights. With the choice Wi = 1 for all i, we have 1+v+r  Wi2 Bi2  v+r  i=2 1/(v+r)  1+v+r  Wi2  Bi2 ≤ (v + r)H02 .  =  (26)  i=2  i=2  If we choose Wi as the positive integer nearest H0 /Bi for all i, then 1+v+r  Wi2 Bi2 i=2 1/(v+r)  1+v+r  ≈  Wi2 i=2  1/(v+r)  1+v+r  1/(v+r)  1+v+r  (v + r)H02  Bi2  = (v + r)  H02 /Bi2  i=2  1+v+r  Bi2 .  ≤ i=2  i=2  (27) We are thus inclined to prefer the second choice of weights over the first. Here, and elsewhere in this thesis, when we refer to the integer nearest to a given real number, we decide arbitrarily whether to round up or down in the case the real number is a half-integer. The correctness of the algorithm is completely insensitive to these decisions. Note that we are free to make a choice for m that is smaller than m0 . A smaller value of m will produce a better upper bound for nl if the hypothesis of Lemma 20.1 is satisfied. However, if the hypothesis of Lemma 20.1 cannot be verified, one will incur the cost of computing another LLL-reduced basis after increasing m. We expect (1/hl ) (1/(pl − 1) − ordpl (δ2 )) to be small, so the upper bound for nl produced by the reduction procedure will generally look like (1/hl )(m − dl ). Therefore, the inequalities (26) and (27) imply that, with m the size of m0 and with either of the two simple choices for the weights considered above, we expect to get a bound of size log H0 , as desired.  51  21  Basic real reduction Now we describe how the basic real reduction procedure works. Under certain conditions, we can feed the improved upper bounds on the nl obtained  through the pl -adic reduction procedures into Lemma 14.1 and combine the result with Lemma 15.1 to immediately obtain a new upper bound on A. In particular, we have the following lemma. Lemma 21.1. If i0 ∈ {s + 1, . . . , s + 2t} and x − yθ(i0 ) = min x − yθ(i) , then for any 1≤i≤n  0 < c11 < c10 /(n − 1) we have c8 + c9 N0 c + c9 N0 − 1, 8 −1 , c10 − (n − 1)c11 c10 − c11  A ≤ max c15 , where N0 = max {N1 , . . . , Nv }.  Proof. This follows immediately from Lemmas 14.1 and 15.1.  Note that c8 , c9 , and c15 are expected to be small and that we are free to choose the parameter c11 in such a way that the upper bound for A in Lemma 21.1 becomes optimal. If s = 0, then {s + 1, . . . , s + 2t} = {1, . . . , n}, and so we must have x − yθ(i0 ) = min x − yθ(i) for some i0 ∈ {s + 1, . . . , s + 2t}. Hence Lemma 21.1 gives a new upper  1≤i≤n  bound on A when s = 0. In the s > 0 case, we will need to use a lattice reduction based Diophantine approximation method (similar to the one used in the basic pl -adic reduction procedures) to improve the bound on A. We first treat the real case (s ≥ 3). Let C, W2 , . . . , Wv+r be positive integers. Later in this section, we will discuss how to choose C and the Wi (the weights) to obtain a good reduction of A0 . Note that log C is the analog of m from the pl -adic reduction procedures. Let i0 ∈ {1, . . . , s}, and let j = j(i0 ), k = k(i0 ), c16 = c16 (i0 ), and Λ0 = Λ0 (i0 ) be as in Section 15. Put (k)  α1 = log |δ1 | ,  α1+i = log  πi  (j)  πi  (k)  (i = 1, . . . , v),  α1+v+i = log  εi  (j)  (i = 1, . . . , r).  εi  52  Then  1+v+r  Λ0 =  bi αi . i=1  For i = 2, . . . , v + r, let φi be the nearest integer to Cαi . Let φ1+v+r be the nearest integer to Cα1+v+r such that |φ1+v+r | ≥ 2, and let φ1 be the nearest integer to Cα1 such that φ1 /φ1+v+r ∈ / Z. We must, of course, compute the αi to precision at least log C/ log 10 to avoid errors here. Let ΓC be the (v +r)-dimensional lattice generated by the column-vectors of the matrix   W2   ..   . 0   AC =  .  0  Wv+r   φ2 · · · φv+r φ1+v+r Put     0  .   .   .  y=  ∈ Zv+r .  0    −φ1  If we had y ∈ ΓC , there would be integers z1 , . . . , zv+r such that y = Am [z1 , . . . , zv+r ]T . This would then force z1 = · · · = zv+r−1 = 0 and −φ1 = zv+r φ1+v+r . But this last equality contradicts the fact that φ1 /φ1+v+r ∈ / Z. Therefore we have y ∈ / ΓC , and, consequently, we will be able to apply Lemma 18.1 to bound l(ΓC , y) from below after computing a LLL-reduced basis for ΓC . Put 1+v+r  v+r  Bi |φi − Cαi | ,  R=  Wi2 Bi2 .  S=  i=1  i=2  Lemma 21.2. Suppose i0 ∈ {1, . . . , s} and x − yθ(i0 ) = min x − yθ(i) . Let D be any 1≤i≤n  number such that l(ΓC , y) ≥ D. If D >  (R2  +  S)1/2 ,  then for any 0 < c11 < c10 /(n − 1)  we have  A ≤ max          1 log(2(log 2)c16 (i0 )) + log C − log (D2 − S)1/2 − R , c11 c8 + c9 N0 c + c9 N0 log(2c16 (i0 )) − 1, 8 − 1, − 1, 0 c10 − (n − 1)c11 c10 − c11 c11          As with Lemma 20.1, we are free to choose c11 in Lemma 21.2 so that the upper bound on A becomes optimal. 53  Proof. Assume l(ΓC , y) > (R2 + S)1/2 . Consider the lattice point     W2 b2   b2 ..   .   .  ..  =  x = AC   + y,      W b v+r v+r   b1+v+r Φ where  1+v+r  Φ=  bi φi . i=1  We have 1+v+r  |Φ| ≤ |Φ − CΛ0 | + |CΛ0 | =  bi (φi − Cαi ) + |CΛ0 | ≤ R + |CΛ0 | , i=1  and so, since y ∈ / ΓC , v+r  l(ΓC , y)2 ≤ |x − y|2 =  Wi2 b2i + |Φ|2 ≤ S + (R + |CΛ0 |)2 . i=2  Since l(ΓC , y) > (R2 + S)1/2 , the inequality above can be rearranged to give l(ΓC , y)2 − S  1/2  − R ≤ |CΛ0 | .  Now assume A≥  c8 + c9 N , c10 − (n − 1)c11  A≥  c8 + c9 N , c10 − c11  A≥  log(2c16 (i0 )) , c11  A≥1  By Lemma 14.1, the first two inequalities imply x − yθ(i0 ) ≤ e−c11 A . Then the third and fourth inequalities give, as in the proof of Lemma 15.3, |Λ0 | ≤ 2(log 2)c16 (i0 )e−c11 A . Therefore we have D2 − S  1/2  − R ≤ 2(log 2)c16 (i0 )Ce−c11 A ,  which is equivalent to A≤  1 log(2(log 2)c16 (i0 )) + log C − log (D2 − S)1/2 − R c11  .  54  Now we describe the reduction procedure. For a given i0 ∈ {1, . . . , n}, we will call a number U an i0 -conditional upper bound for A if A ≤ U holds in the case x − yθ(i0 ) = min x − yθ(i) . For each i0 ∈ {1, . . . , n}, we will use A0 (i0 ) to denote the best i0 -  1≤i≤n  conditional upper bound for A that we have at the current stage in the procedure. At the start of the procedure, A0 (i0 ) = A0 for every i0 ∈ {1, . . . , n}. For each i0 ∈ {1, . . . , s} in turn, we compute an LLL-reduced basis for ΓC , and then use Lemma 18.1 to find a lower bound D for l(ΓC , y). If D is greater than (R2 + S)1/2 , Lemma 21.2 gives an i0 -conditional upper bound for A that we hope reduces A0 (i0 ). If D ≤ (R2 + S)1/2 , we should increase C somewhat and try again. Furthermore, when D is greater than (R2 + S)1/2 , but the i0 -conditional bound produced by Lemma 21.2 does not improve A0 (i0 ), we should also increase C and try again. As in Section 20, if C needs to be increased to C we should take as input to the LLL algorithm the partially reduced basis for ΓC given by the columns of AC UC (where UC is the unimodular integer matrix for which the columns of AC UC form the LLL-reduced basis we computed for ΓC ) rather than the basis given by AC . Once we run through all i0 ∈ {1, . . . , s}, we use Lemma 21.1 to compute a number that is an i0 -conditional upper bound A for each i0 ∈ {s + 1, . . . , s + 2t}. Since we must have x − yθ(i0 ) = min x − yθ(i) for some i0 ∈ {1, . . . , n}, we know 1≤i≤n  max  i0 ∈{1,...,n}  A0 (i0 ) is an  unconditional upper bound for A. Note that this will be an improvement on the upper bound for A we had at the start of the procedure if and only if every i0 -conditional upper bound for A calculated in the procedure is smaller than the starting upper bound for A. Therefore, if, for a given i0 ∈ {1, . . . , s}, we have found no new i0 -conditional upper bound for A after several increases of C, and the value of C has become significantly larger than it was initially, then we should terminate the procedure (there is no point in moving on to the next value of i0 ∈ {1, . . . , s}). Now we discuss how to choose C and the weights Wi . To optimize the i0 -conditional upper bounds for A produced by Lemma 21.2, we want the expression log(2(log 2)c16 (i0 )) + log C − log((D2 − S)1/2 − R)  (28)  to be as small as possible while still ensuring D > (R2 + S)1/2 . Here D is the lower bound for l(ΓC , y) from Lemma 18.1. Arguing heuristically as in Section 20, we see that D is of the size of 2−(v+r)/2 C |α1+v+r |  v+r i=2  Wi  1/(v+r)  . Using that R ≈  1+v+r i=1  Bi /2, we find  55  that D > (R2 + S)1/2 is essentially equivalent to the inequality C > C0 , where     C0 =     2  1+v+r  Bi /2  (v+r)/2  v+r  Wi2 Bi2  +  i=1      2/(v+r)    i=2 v+r  2−(v+r)  |α1+v+r |  Wi  .  i=2  It follows that as C decreases towards C0 , D decreases towards (R2 + S)1/2 , and, therefore, − log (D2 − S)1/2 − R increases towards infinity. However, − log (D2 − S)1/2 − R ≤ 0 if we have D > ((R + 1)2 + S)1/2 , which is essentially equivalent to     C>    2  1+v+r  (v+r)/2  v+r  Wi2 Bi2    i=1 i=2  2/(v+r)  v+r  −(v+r) 2 |α1+v+r | Wi 1+  Bi /2  +  .  i=2  The difference between the expression on the right-hand side of this inequality and C0 is negligible in our approximation. Therefore, we can safely choose a value the size of C0 for C, and this choice is essentially the best possible with respect to minimizing the contribution of log C to the upper bound for A. We can do better with the bound for A if we try to minimize the contribution of the expression log C − log (D2 − S)1/2 − R as a whole. This expression will be essentially minimized if we select C so that the two terms are equal, i.e, if C −1 = (D2 − S)1/2 − R. Using the same approximations for D and R as before, this leads to a polynomial equation for C like  2  v+r  −(v+r)2  2  |α1+v+r |  Wi  2  1+v+r  C 2(v+r+1) =  1 + C  i=2  Bi /2 i=1  v+r  + C2  v+r Wi2 Bi2   .  i=2  We can try to find an approximate solution to this equation that satisfies C > C0 and use that as our choice of C. As long as we choose weights that are independent of C, we can solve this equation numerically. An easier method is to start with a value for C of the size of C0 , and then increment C (with some convenient step size) until C −1 ≈ (D2 −S)1/2 −R, where D ≈ 2−(v+r)/2 (C |α1+v+r |  v+r i=2  Wi )1/(v+r) .  For the weights Wi , either choosing Wi = 1 for all i or choosing Wi to be the nearest positive integer to H0 /Bi =  max Bj /Bi for all i works well. It is not immediately  2≤j≤v+r  obvious that one choice of weights is strictly better than the other. However, the second  56  choice tends to give a more balanced lattice, which improves the quality of the lower bound on l(Γ, y) and the quality of the heuristics we used above. We expect that the maximum of the upper bounds for A coming from Lemmas 21.2 and 21.1 will be of the size log C. Since the discussed choices for C and the weights Wi will tend to give log C ≈ log H0 , we thus expect a new bound for A like log H0 . The complex case (s = 1, 2) is nearly identical to the real case. Let i0 ∈ {1, . . . , s}, and let j = j(i0 ), k = k(i0 ), c16 = c16 (i0 ), Λ0 = Λ0 (i0 ), and a0 = a0 (i0 ) be as in Section 15. Let C, W2 , . . . , W1+v+r be positive integers. We will discuss how to choose C and the weights Wi at the end. Put b2+v+r = 2a0 . It follows from the proof of Lemma 15.3 that 1+v+r i=1  |b2+v+r | is bounded by B2+v+r = 2 sin−1 (1/4)/π +  Bi . Define  (k)  α1 = Im (Log(δ1 )) ,  α1+i = Im Log  πi  (i = 1, . . . , v),  (j)  πi  (k)  α1+v+i = Im Log  εi  (j)  (i = 1, . . . , r),  εi  Then  α2+v+r = Im (Log(−1)) = π.  2+v+r  Λ0 =  bi αi . i=1  For i = 2, . . . , 1 + v + r, let φi be the nearest integer to Cαi . Let φ1+v+r be the nearest integer to Cα2+v+r such that |φ2+v+r | ≥ 2 and let φ1 be the nearest integer to Cα1 such that φ1 /φ2+v+r ∈ / Z. Let ΓC be the (1 + v + r)-dimensional lattice generated by the column-vectors of the matrix  W2  ..  .  AC =   0  φ2 · · · Put   0 W1+v+r φ1+v+r     .    φ2+v+r     0  .   .   .  y=  ∈ Z1+v+r .  0    −φ1  As in the real case, y ∈ / ΓC , so Lemma 18.1 can be applied to bound l(ΓC , y) from below.  57  It is easily proved that Lemma 21.2 holds with 2+v+r  1+v+r  Bi |φ − Cαi | ,  R=  Wi2 Bi2 ,  S=  i=1  i=2  and with the expression 2(log 2) replaced by 4 sin−1 (1/4). The reduction procedure runs exactly as in the real case. An analysis like the one from the real case indicates choosing     C≈    2  2+v+r  Bi /2  (v+r+1)/2  1+v+r  Wi2 Bi2  +  i=1  i=2 1+v+r  2−(v+r+1)  |α2+v+r |  Wi      2/(v+r+1)    i=2  is optimal when it comes to minimizing the contribution of the log C term in the bound produced by (the complex case version of) Lemma 21.2. Adjusting the value of C a bit so that C −1 is closer to (D2 − S)1/2 − R (where we use the approximation D ≈ 2−(v+r+1)/2 C |α2+v+r |  1+v+r i=2  Wi  1/(1+v+r)  ) will help improve the bound further. The  choice of weights Wi = 1 for all i is, of course, valid. For the same reason as in the real case, taking Wi equal to the nearest positive integer to H0 /Bi =  max  2≤j≤1+v+r  Bj /Bi for all i  tends to be preferable.  58  22  Refined pl -adic reduction In this section, we explain the refined pl -adic reduction procedure. Fix l ∈ I. Let m be a positive integer. The solutions of (14) fall into one of two cases:  Case 1. nl >  1 − ordpl (δ2 ) pl − 1  1 hl  nl ≥  and  1 (m − dl ) hl  Case 2. nl ≤ max  1 hl  1 − ordpl (δ2 ) pl − 1  ,  1 (m − dl ) − 1 hl  The refined pl -adic reduction procedure is essentially a technique to efficiently find all the solutions of (14) in the Case 1. So, at the end of the procedure, we will then know all the solutions that have yet to be found satisfy nl ≤ max {(1/hl ) (1/(pl − 1) − ordpl (δ2 )) , (1/hl )(m − dl ) − 1} . Thus, if m is small enough, we will have found an improvement of the upper bound for nl . We will further discuss the choice of m later in this section. Choose positive integers W2 , . . . , W1+v+r with W2 , . . . , Wv+1 even. As with m, we postpone the details of how to choose the Wi until later in this Section. Define Γm , Am , and λ as in Section 20. If 2 ≤ ˆi ≤ v + 1, set   1 2 W2 B2      ..   .     1     2 Wˆi−1 Bˆi−1   1   2 Wˆi+1 Bˆi+1     ..   .  ∈ Zv+r ;  y=  1   2 Wv+1 Bv+1     0     .   ..       0   {m} 1 −Wˆi β1 + 2 Wˆi Bˆi  59  otherwise set    1 2 W2 B2      ..     .   1W B   2 v+1 v+1     ∈ Zv+r . y= 0     ..   .       0   {m} −Wˆi β1 Choose a vector z ∈ Γm that is close to y. An efficient way to do this is as follows. Compute a matrix Bm whose column-vectors c1 , . . . , cv+r form an LLL-reduced basis for Γm , and write y = s1 c1 + · · · + sv+r cv+r ,  si ∈ R  −1 y). Choose t ∈ Zv+r such that |t − s | ≤ 1 (in other words, compute [s1 , . . . , sv+r ]T = Bm i i  for all i and |y − Bm t| is minimal. Then Bm t is likely the closest lattice vector to y, so we take z = Bm t. Set v+1  D= i=2  1 Wi Bi 2  1/2  1+v+r  2  +  (Wi Bi )  2  ,  D0 = D + |y − z| .  i=2+v  Lemma 22.1. In Case 1, the tuple (b2 , . . . , b1+v+r ) satisfies x − z ∈ Γm and |x − z| ≤ D0 , where   b2    ..   .     b   ˆi−1     x = Am   bˆi+1  .  .   ..      b1+v+r    λ   Proof. Suppose nl > (1/hl ) (1/(pl − 1) − ordpl (δ2 )) and nl ≥ (1/hl )(m − dl ). Then, as in the proof of Lemma 20.1, λ ∈ Z. So x belongs to Γm , and, therefore, x − z ∈ Γm also. If  60  2 ≤ ˆi ≤ v + 1, then     W2 b2 − 12 W2 B2 .. .           Wˆ bˆ − 1 Wˆ Bˆ   i−1 i−1 2 i−1 i−1     Wˆi+1 bˆi+1 − 12 Wˆi+1 Bˆi+1      ..   . ,  x−y =  1 Wv+1 bv+1 − 2 Wv+1 Bv+1      Wv+2 bv+2     .   ..       W1+v+r b1+v+r   1 Wˆi bˆi − 2 Wˆi Bˆi while if v + 2 ≤ ˆi ≤ 1 + v + r, we have   (29)    W2 b2 − 21 W2 B2 .. .          Wv+1 bv+1 − 1 Wv+1 Bv+1    2     Wv+2 bv+2     ..   .  . x−y =    Wˆi−1 bˆi−1     Wˆi+1 bˆi+1     ..   .       W1+v+r b1+v+r   Wˆi bˆi  (30)  Either way, v+1  |x − y| ≤ i=2  1 Wi Bi 2  1/2  1+v+r  2  2  +  (Wi Bi )  = D.  i=2+v  Hence the lattice vector x − z must satisfy |x − z| = |x − y| + |y − z| ≤ D0 .  We now use the Fincke-Pohst algorithm to efficiently compute all vectors u ∈ Γm with |u| ≤ D0 . Each such u is a candidate to have u = x − z. For each u, we compute 61  the corresponding tuple (b2 , . . . , b1+v+r ) assuming u = x − z. This assumption lets us write x − y = u + z − y, and so, since u, y, z are known explicitly, we can easily compute (b2 , . . . , b1+v+r ) using (29) or (30), as appropriate. Each tuple (b2 , . . . , b1+v+r ) that satisfies (14) (for some x, y) and satisfies the Case 1 inequalities must be one of the tuples computed in this way. However, the computed tuples are not necessarily all solutions of (14), so they will need to actually be tested for (14). This can be done, for example, by computing the coefficients of the right-hand side of (14) and verifying that the coefficients of θ2 , . . . , θn−1 of (14) all vanish. However, due to the large number of tuples likely to be computed, it is not practical at this stage to test every tuple for (14) immediately. It is preferable to first perform on each tuple a series of tests (see below) that rule-out non-solutions with minimal computational effort. Then, if a tuple manages to survive these tests, we can test it for (14). In practice, very few non-solutions will survive the series of computationally cheap tests. One could also choose to store those tuples that pass the series of computationally cheap tests for further testing later, rather than test the tuple for (14) at this stage. We now make a remark on implementation. There are likely to be a large number of lattice vectors with norm less than or equal to D0 . To save on memory usage, immediately after each vector u is found, one should extract the tuple, test it, and, if and only if it corresponds to a solution, store it. One should not store all the computed vectors or all the extracted tuples. Now we discuss a series of efficient tests that we can apply to the tuple (b2 , . . . , b1+v+r ) to eliminate a non-solution. Note that the remarks in Section 19 about verifying the conclusions of Lemmas 8.2 and 19.1 concern the last few tests we will describe below. As a first test, we check that the bi are all integers. After that, we check that the tuple satisfies the current bounds for the bi : |bi | ≤ Bi for all i, and b2 , . . . , b1+v ≥ 0. Next, we eliminate the tuple if it satisfies nl ≤ max {(1/hl ) (1/(pl − 1) − ordpl (δ2 )) , (1/hl )(m − dl ) − 1} because we are only looking for those solutions that fall into Case 1. By Lemma 19.1, a tuple that survives the last test must satisfy ordpl (Λl ) ≥ nl hl + dl if it corresponds to a solution. If this inequality does not hold, we eliminate the tuple. Note that if we are in the special case described in Section 19, Lemma 19.1 implies the tuple must actually satisfy ordpl (Λl ) = nl hl + dl . At this point, we have verified that the tuple does not contradict the instance of Lemma 19.1 corresponding to our fixed l ∈ I. We next check that the tuple does not contradict Lemma 19.1 for those indices l1 ∈ I with l1 = l. More precisely, for each l1 ∈ I \{l} with nl1 > (1/hl1 )(1/(pl1 −1)−ordpl1 (δ2 )), we check whether ordpl1 (Λl1 ) ≥  62  nl1 hl1 + dl1 holds (whether ordpl1 (Λl1 ) = nl1 hl1 + dl1 holds if we are in the special case) and discard the tuple if not. Now, a tuple that has survived up to this stage must satisfy nl > (1/hl ) (1/(pl − 1) − ordpl (δ2 )) (a tuple with nl ≤ (1/hl ) (1/(pl − 1) − ordpl (δ2 )) would have been eliminated at a previous stage). Hence, if the tuple corresponds to a solution, Lemma 8.2 implies that ordpl (Λl ) = nl hl + ordpl (δ2 ). If this equation does not hold, we eliminate the tuple. Note that there is no point in checking this equation if we are in the special case (see the comments made in Section 19). Finally, if the tuple has still not been ruled-out, we test it for the versions of Lemma 8.2 corresponding to those indices l1 ∈ I \ {l} for which the general case of Section 19 applies. That is, for each such index l1 , if nl1 > (1/hl1 )(1/(pl1 −1)−ordpl1 (δ2 )), we check whether ordpl1 (Λl1 ) = nl1 hl1 +ordpl1 (δ2 ), and, if this equality does not hold, we discard the tuple. Note that it is easy to compute Λl and Λl (and Λl1 and Λl1 ) because the αi and βi will have already been computed and the bi are given to us. Note that it is possible to make a different choice for y. However, the one we have chosen produces a bound D0 that is reasonably small in terms of the weights. For a given lattice and numbers 0 < D1 < D2 , it is of course cheaper to enumerate the smaller set consisting of those lattice vectors with norm less than D1 than to enumerate the larger set of lattice vectors with norm less than D2 . Since the parameters m and Wi determine the lattice, it is advantageous to have D0 be small in terms of them. Now we discuss how to choose the weights. If the Wi are taken to be small, D0 will also be small and we might hope that this will make the process of enumerating all the vectors with norm less than or equal to D0 fast. However, small weights produce short basis vectors for the lattice ΓC , which in turn produce more short vectors in the lattice overall. This offsets the decrease in the norm bound. Hence having smaller weights does not necessarily reduce the enumeration cost. There is a balance to be struck between the size of D0 and the number of short vectors in the lattice. The following choice works well. For i = 2, . . . , v + 1, define Wi so that 12 Wi is the nearest positive integer to H0 /Bi . For i = v + 2, . . . , 1 + v + r, let Wi be the nearest positive integer to H0 /Bi . This choice also prevents the lattice from being badly skewed (having a skewed lattice makes the enumeration more difficult). Finally, we discuss the value of m. To make the new upper bound for nl as small as possible, we should take m as small as possible. Unlike with the simple pl -adic reduction, there is now no condition (like l(Γm , y) > Q1/2 ) to limit how small m can theoretically 63  be chosen. However, if we take m too small, the lattice Γm will have so many vectors of norm less than or equal to D0 that the computational cost to enumerate (and test) them all will be prohibitive. Choosing m as in Section 20 seems to work well in practice. In fact, we have found that a significantly smaller choice of m (like 3/4 the size suggested in Section 20) works fine. Note that it is possible to estimate the cost of the Fincke-Pohst enumeration for a given lattice and norm bound before performing the enumeration. If the estimated cost is too large, one should increase m and try the procedure again. If several increases of m yield no new upper bound for nl , we should move on to the next l ∈ I (or onto the real reduction if there is no next l ∈ I).  64  23  Refined real reduction Here we describe the refined real reduction procedure. The outline of the refined real reduction procedure is the same as for the basic pro-  cedure. If s = 0, Lemma 21.1 immediately gives a new upper bound for A exactly as in the basic procedure. For the s > 0 case, we first perform lattice computations to find i0 -conditional upper bounds for A for each i0 ∈ {1, . . . , s} and use Lemma 21.1 to find an upper bound on A that is i0 -conditional for every i0 ∈ {s + 1, . . . , s + 2t}. Then the maximum of all these upper bounds is taken as an unconditional upper bound for A. We describe below how the i0 -conditional upper bounds for A are computed for i0 ∈ {1, . . . , s}. This is the only point on which the refined and basic reduction procedures differ. Suppose first that we are in the real case (s ≥ 3). Let C, W2 , . . . , Wv+r be positive integers with W2 , . . . , Wv+1 even. We will discuss how to choose C and the weights Wi later in this section. Let i0 ∈ {1, . . . , s} and let j = j(i0 ), k = k(i0 ), c16 = c16 (i0 ), and Λ0 = Λ0 (i0 ) be as in Section 15. Define αi , φi (i = 1, . . . , 1 + v + r), AC , ΓC , R, and S as in Section 21. Put    1 2 W2 B2      ..     .   1W B   2 v+1 v+1     ∈ Zv+r y= 0     ..   .       0   −φ1 Choose a vector z ∈ ΓC that is close to y (see Section 22 for a method to do this). Choose a number D > (R2 + S)1/2 and set D0 = D + |y − z| . Let c11 be any number satisfying 0 < c11 < c10 /(n − 1). The solutions of (14) are divided into two cases depending on A: Case 1.   1 2 1/2   log(2(log 2)c (i )) + log C − log((D − S) − R) ,   16 0 c11 A ≥ max c8 + c9 N0 c + c9 N0 log(2c16 (i0 ))     , 8 , ,1 c10 − (n − 1)c11 c10 − c11 c11 65  Case 2. A ≤ max          1 − 1, log(2(log 2)c16 (i0 )) + log C − log (D2 − S)1/2 − R c11 c8 + c9 N0 c + c9 N0 log(2c16 (i0 )) − 1, 8 − 1, − 1, 0 c10 − (n − 1)c11 c10 − c11 c11          Note that one should select c11 to minimize the upper bound for A in Case 2. The main computational step in the procedure is finding all the solutions of (14) that fit the first case and that have x − yθ(i0 ) = min x − yθ(i) . Once that is done, we know 1≤i≤n  that all the solutions of (14) with x − yθ(i0 ) = min x − yθ(i) that still need to be found 1≤i≤n  belong to the second case. So, if C is small enough, we will have found an improvement of the upper bound for A subject to the condition x − yθ(i0 ) = min x − yθ(i) . This is 1≤i≤n  the i0 -conditional upper bound for A we seek. Lemma 23.1. Suppose i0 ∈ {1, . . . , s} and x − yθ(i0 ) = min x − yθ(i) . In Case 1, the 1≤i≤n  tuple (b2 , . . . , b1+v+r ) satisfies x − z ∈ ΓC and |x − z| ≤ D0 , where   b2  .  .  x = AC   . . b1+v+r Proof. Since x and z both belong to ΓC , x − z ∈ ΓC as well. By Lemma 14.1 and the inequalities A≥  c8 + c9 N , c10 − (n − 1)c11  A≥  c8 + c9 N , c10 − c11  we have x − yθ(i0 ) ≤ e−c11 A . Then, as in the proof of Lemma 15.3, it follows from the inequality A ≥ max { log(2c16 (i0 ))/c11 , 1} that |Λ0 | ≤ 2(log 2)c16 (i0 )e−c11 A . So since   W2 b2 − 21 W2 B2 .. .            W b  1 − W B  v+1 v+1 2 v+1 v+1     x−y = W b v+2 v+2     ..   .       Wv+r bv+r   Φ  (31)  66  with  1+v+r  Φ=  bi φi , i=1  we have |x − y|2 ≤ S + Φ2 ≤ S + (|CΛ0 | + |CΛ0 − Φ|)2 ≤ S + 2(log 2)c16 (i0 )Ce−c11 A + R  2  .  As A≥  1 log(2(log 2)c16 (i0 )) + log C − log((D2 − S)1/2 − R) , c11  it follows that |x − y|2 ≤ D2 , whence |x − z| ≤ D0 .  Lemma 23.1 justifies the following method for computing the solutions of (14) in Case 1 having x − yθ(i0 ) = min x − yθ(i) . We compute (using the Fincke-Pohst algorithm) 1≤i≤n  all vectors u ∈ ΓC with |u| ≤ D0 . For each such u, we compute the corresponding tuple (b2 , . . . , b1+v+r ) assuming u = x − z. This assumption lets us write x − y = u + z − y, so, since u, y, z are known explicitly, we can easily compute (b2 , . . . , b1+v+r ) using (31). We then put the tuples through a series of tests (see below) that will eliminate most nonsolutions through a small amount of computation. Finally, the few tuples that remain are tested for (14). As with the refined pl -adic reduction procedure, it would be impractical to simply test in (14) every tuple we compute. The tests we apply to the tuple (b2 , . . . , b1+v+r ) are the essentially the same as in the refined pl -adic reduction. First, we check that the bi are all integers and that the current bounds b2 , . . . , b1+v ≥ 0 and |bi | ≤ Bi hold. Next, if the tuple satisfies the Case 2 inequality for A (i.e., the soon to be new i0 -conditional upper bound for A), then it can be discarded because we are only looking for tuples that fit into Case 1. After that, we check, for each l ∈ I, that the tuple does not contradict Lemma 19.1. If a tuple passes those tests, we perform the same check for Lemma 8.2 for all l ∈ I. Note that this last test is redundant for those l ∈ I for which we are in the special case described in Section 19. Let us now discuss the choice of C. As it was in Section 22 with m and Γm , taking C too small will produce a lattice ΓC that has more vectors with norm less D0 than can be enumerated in a reasonable amount of time. It seems to work well in practice to choose C somewhat (but not too much) smaller than suggested in Section 21. For instance, a reasonable choice is to select a value of C that makes log C about 3/4 the size it would be if one used the value for C suggested in Section 21. 67  It is recommended that one estimates the cost of the enumeration before performing it. If the estimate is too large, one should increase C, recalculate the necessary quantities (like a basis for ΓC ) and estimate the enumeration cost again. Once a small enough estimate is found, the enumeration can proceed. If several increases of C have yielded no new i0 conditional upper bound for A and C has become significantly larger than it was initially, the procedure should be terminated. It is advantageous to choose a small value of D to keep the cost of the enumeration down. However, taking D too close to its lower limit (R2 + S)1/2 will cause the term − log((D2 − S) − R) in the i0 -conditional upper bound for A (i.e, in the Case 2 inequality) to blow up. Note that the choice D = ((R + 1)2 + S)1/2 is reasonably close (R2 + S)1/2 and makes − log((D2 − S) − R) = 0. Now comes the choice of the weights. Since S =  v+1 i=2  2 1 2 Wi Bi  +  v+r 2 i=v+2 (Wi Bi ) ,  the smaller the weights are, the smaller D can be. For a given lattice, a smaller value of D leads to a lower cost to enumerate the vectors of norm less than D. However, the lattice ΓC depends on the weights, and smaller weights tend to produce shorter vectors in the lattice overall. In terms of the enumeration cost, this last phenomenon tends to counteract the decrease in D that smaller weights produce. There is a balance to be struck between the size of D and the size of the weights. The following choice of weights seems to work well. For i = 2, . . . , 1 + v, choose Wi so that 12 Wi is the nearest positive integer to max Bj /Bi . For i = 2+v, . . . , v +r, Wi is the nearest positive integer to  2≤j≤v+r  max Bj /Bi .  2≤j≤v+r  The complex case (s = 1, 2) is identical to the s ≥ 3 case except for a few modifications. We let C, W2 , . . . , W1+v+r be positive integers with W2 , . . . , Wv+1 even. Let i0 ∈ {1, . . . , s} and let j = j(i0 ), k = k(i0 ), c16 = c16 (i0 ), Λ0 = Λ0 (i0 ), and a0 = a0 (i0 ) be as in Section 15. Define αi , φi (i = 1, . . . , 2 + v + r), b2+v+r , AC , ΓC , R, and S as in Section 21. Define y as in the real case but with an extra zero entry so that y ∈ Zv+r+1 . Choose a vector z in ΓC close to y and a number D > (R2 + S)1/2 . The two cases into which we divide the solutions of (14) are: Case 1.  1   log(4 sin−1 (1/4)c16 (i0 )) + log C − log((D2 − S)1/2 − R) ,    c11 A ≥ max c8 + c9 N0 c + c9 N0 log(2c16 (i0 ))     , 8 , ,1 c10 − (n − 1)c11 c10 − c11 c11  68  Case 2.  A ≤ max          1 log(4 sin−1 (1/4)c16 (i0 )) + log C − log((D2 − S)1/2 − R) , − 1 c11 c8 + c9 N0 c + c9 N0 log(2c16 (i0 )) − 1, 8 − 1, − 1, 0 c10 − (n − 1)c11 c10 − c11 c11          Here c11 is a parameter to be chosen strictly between 0 < c11 < c10 /(n − 1). It is advantageous to choose c11 in such a way that the upper bound for A in Case 2 is minimized. Now Lemma 23.1 holds with x = AC [b1 , . . . , b2+v+r ]T and with (b1 , . . . , b1+v+r ) replaced by (b1 , . . . , b2+v+r ). The method for computing the solutions of (14) in Case 1 having x − yθ(i0 ) = min x − yθ(i) runs as before, but with the tuple (b1 , . . . , b2+v+r ). There 1≤i≤n  are a couple of additional tests that we can perform on the tuple (b1 , . . . , b2+v+r ). Namely, we can check that b2+v+r is an even integer (since it should be equal to 2a0 ) and that |b2+v+r | ≤ B2+v+r . The considerations for the choices of D, C, and the Wi are analogous to the s ≥ 3 case. We note that the choice of weights should be modified as follows. For i = 2, . . . , 1 + v, choose Wi so that 21 Wi is the nearest positive integer to For i = 2 + v, . . . , 1 + v + r, choose Wi as the nearest positive integer to  max  Bj /Bi .  max  Bj /Bi .  2≤j≤1+v+r 2≤j≤1+v+r  69  24  The sieving procedure In this final stage, we have upper bounds N1 , . . . , Nv , A0 for n1 , . . . , nv , A = max |ai |,  respectively, that (we hope) are very small. We therefore have (N1 +1) · · · (Nv +1)(2A0 +1)r tuples (n1 , . . . , nv , a1 , . . . , ar ) to test as solutions to (14). We can do this by checking whether the coefficients of θ2 , . . . , θn−1 for the right-hand side of (14) are all zero. Since the number of tuples to test is likely very large, the cost of the field arithmetic involved makes this method impractical. We thus prefer the following strategy that uses chiefly modular arithmetic to sieve the set of tuples. First some set-up. Let q be a rational prime having at least three distinct degree one prime ideals q1 , q2 , q3 in its factorization in OK . Since OK /qi ∼ = Z/qZ for i = 1, 2, 3, we can find, for each i, explicit rational integers mi , Ai , Pi1 , . . . , Piv , Ei1 , . . . , Eir such that θ ≡ mi ,  αζ ≡ Ai ,  πj ≡ Pij (j = 1, . . . , v),  εj ≡ Eij (j = 1, . . . , r)  (mod qi ).  It follows from (14) that n1 nv a1 ar x − ymi ≡ Ai Pi1 · · · Piv Ei1 · · · Eir  (mod qi )  (i = 1, 2, 3).  Note that each of these congruences holds modulo q as well. So combining these congruences with the identity (m2 − m3 )(x − ym1 ) + (m3 − m1 )(x − ym2 ) = (m2 − m1 )(x − ym3 ) yields n1 n1 ar nv a1 ar nv a1 E21 · · · E2r + (m3 − m1 )A2 P21 · · · P2v (m2 − m3 )A1 P11 · · · P1v E11 · · · E1r n1 nv a1 ar ≡ (m2 − m1 )A3 P31 · · · P3v E31 · · · E3r  (32)  (mod q).  Since (32) is an integer congruence, testing the tuple (n1 , . . . , nv , a1 , . . . , ar ) for it is computationally easy. The sieving procedure runs as follows. We select several primes q1 , . . . , qk that each have at least three distinct degree one prime ideals in their factorizations in OK . For each q ∈ {q1 , . . . , qk }, we compute the integers mi , Ai , Pi1 , . . . , Piv , Ei1 , . . . , Eir (i = 1, 2, 3). Each tuple (n1 , . . . , nv , a1 , . . . , ar ) is then tested for the congruences (32) modulo q = q1 , . . . , qk . Heuristically, we expect that only one out of q random tuples will satisfy (32) modulo q. Thus, it is efficient to check the congruences in decreasing order of the sizes 70  of the qj . Moreover, we expect all the non-solutions to be eliminated by the end of the procedure provided we select primes q1 , . . . , qk such that q1 · · · qk is at least as large as the number of tuples to be tested. If the tuple survives every congruence test, we check it for (14) and then finally for (4) itself (utilizing (15)). Note the method of checking (14) described above gives the values of x and y. We can also skip the check of (14) and check (4) immediately. To do this, we need to compute the x and y corresponding to the tuple (n1 , . . . , nv , a1 , . . . , ar ). This can be done as follows. Put β = αζεa11 · · · εar r π1n1 · · · πvnv and choose two embeddings of K into C: θ → θ(i) (i = 1, 2). By (14), x − yθ(1) = β (1) , and so x = β (1) − θ(1)  β (1) − β (2) , θ(1) − θ(2)  x − yθ(2) = β (2) ,  y=−  β (1) − β (2) . θ(1) − θ(2)  If K is not totally real, we need only look at one embedding. For if θ → θ(1) ∈ C \ R, then with θ(2) = θ(1) the above gives x = β (1) − θ(1)  Im β (1) , Im θ(1)  y=−  Im β (1) . Im θ(1)  71  25  Conclusion In this thesis, we presented and proved the correctness of an algorithm to completely  solve an arbitrary Thue-Mahler equation. We also presented an implementation the algorithm as a computer program using the Magma computer algebra system. The algorithm itself is due essentially to Tzanakis and de Weger [TW2], though our presentation introduced some minor modifications. Our implementation of the algorithm is completely original, and, to the best of our knowledge, it is the first fully general implementation. There are several potential applications for our Thue-Mahler equation solver (i.e., the program we have written). In [BD], Bennett and Dahmen show that the problem of solving the generalized superelliptic equation F (x, y) = z l  (33)  in integers x, y, z, l with (x, y) = 1, where F (x, y) is an irreducible binary form over Z, is closely tied to the problem of solving families of Thue-Mahler equations. In particular, they show that, for a large, explicit class of irreducible binary forms F (x, y) ∈ Z[x, y] of degree 3, 4, 6, or 12, the equation (33) has at most finitely solutions in integers x, y, z, l with (x, y) = 1 and l sufficiently large whenever an associated pair of Thue-Mahler equations have no solutions in integers. Hence, one can use our Thue-Mahler equation solver to prove that many specific generalized superelliptic equations (33) have only finitely many integer solutions when l is large. Moreover, since our Thue-Mahler equation solver makes it possible to solve a large number of Thue-Mahler equations in a reasonable time frame with minimal personal effort on the part of the researcher, it may be useful in further developing the connection between solving generalized superelliptic equations and solving families of Thue-Mahler equations by allowing one to test conjectures and heuristics. Indeed, Bennett and Dahmen use a Thue-Mahler equation solver for degree three equations for this purpose in [BD]. Our Thue-Mahler equation solver can also be applied to the task of determining all elliptic curves over Q having prescribed conductor. Indeed, the problem of determining all elliptic curves of conductor N = pa11 . . . pav v (where the pi are given rational primes, and the ai are given nonnegative integers) can generally be reduced to the task of solving finitely many Thue-Mahler equations involving the primes p1 , . . . , pv . Note that finding all the elliptic curves of conductor 11 was the impetus for Agrawal, Coates, Hunt, and van der Poorten to solve the Thue-Mahler equation x3 − x2 y + xy 2 + y 3 = ±11z using 72  linear forms in logarithms (see [ACHP]). As we mentioned in Section 1, the method used for solving this equation inspired Tzanakis and de Weger to develop their algorithm. The principle method that has been used to compute elliptic curves of a given conductor is the so-called modular symbol method. In fact, this method has been used by J. Cremona to determine all elliptic curves over Q of conductor less than 19000 (see [Cr] for a description of Cremona’s work for curves with conductor up to 13000). However, it may be that the Thue-Mahler equation method for computing elliptic curves over Q is superior to the modular symbol method for conductors having certain forms. Another potential future research direction that stems even more directly from this thesis would be to perform a detailed complexity analysis for the algorithm we presented. Having access to a fully-general implementation of the algorithm will certainly be useful for one wishing to undertake such an analysis. There are a few improvements that can be made to the algorithm presented in this thesis. For one thing, there are better results available for linear forms in real/complex and p-adic logarithms in the special case of two or three logarithms than the general results of Matveev [Mat] and Yu [Yu2] that we have used (see [BL], [La], [Mi1], and [Mi2]). Using the superior results would produce a smaller upper bound for H in Section 16. This would (potentially) reduce the computation time for the reduction procedures by reducing the total number of iterations of the procedures and by reducing the sizes of the entries in the basis vectors generating the approximation lattices (which would speed up the LLL algorithm and the Fincke-Pohst algorithm). Note, however, that a substantial reduction in relative computation time would be obtained only when the general theorems of Matveev and Yu produce a bound on H that is was very much larger than the bound produced by the theorems for two or three logarithms. Such a large discrepancy in the size of the bounds is unlikely to occur as the general results and the two/three-logarithm results depend on a common set of parameters, and do so in roughly the same way. Another modification that can be made to the algorithm concerns the choice of approximation lattices in the pl -reduction procedures, particularly, in the general case described in Section 19. When we choose the index h ∈ {1, . . . , s} in the general case, we are effectively choosing which coefficient Λlh of Λl =  s h−1 h=1 Λlh φ  we will be trying to prove  has small pl -adic valuation. However, what we really want is to prove that Λl has small pl -adic value. (Considering Lemmas 8.1 and 8.2 should make all this clear.) So, since ordpl (Λl ) ≥ min ordpl (Λlh ), and since working with the element Λl of Qpl (φ) directly 1≤h≤s  73  presents problems when it comes to defining an approximation lattice, we should aim to prove that Λlh has small pl -adic valuation for every h ∈ {1, . . . , s}. One way to do this would be to run the whole reduction procedure for each h ∈ {1, . . . , s} separately. However, a more efficient way is to consider each h ∈ {1, . . . , s} simultaneously by working, not with the (v + r)-dimensional lattice Γm generated by the columns of the matrix Am (see Section 20), but with the (v + r + s − 1)-dimensional lattice generated by the columns of the matrix  W2  ..  .       0   Am =       {m} Wˆi β2,1 · · ·   ..  .  {m}  Wˆi β2,s  ···    Wˆi−1  0 Wˆi+1 ..  . W1+v+r  {m} Wˆi βˆi−1,1  .. .  {m}  {m} Wˆi βˆi+1,1  ···  .. .  {m}  Wˆi βˆi−1,s Wˆi βˆi+1,s · · ·  {m}  ··· Wˆi β1+v+r,1 Wˆi pm l .. .. . . {m}  Wˆi β1+v+r,s  0  ···            ,      0      m Wˆi pl  ˆ are indices where βi,h = αih /αˆihˆ for i = 1, . . . , 1 + v + r and h = 1, . . . , s, and where ˆi and h in {2, . . . , 1 + v + r} and {1, . . . , s}, respectively, for which ordpl (αˆihˆ ) =  min  2≤i≤1+v+r  min ordpl (αih ) .  1≤h≤s  We are assuming here, of course, that l ∈ I. With this modification to the approximation lattices, analogs of Lemmas 20.1 and 22.1 are readily established, and both the basic and refined pl -adic reduction procedures work virtually the same as before (cf. Chapter IV of Smart’s book [Sm]). The best modern versions of the LLL algorithm have worstcase running time O(d3 (d + log B)(log B)M (d)), where d denotes the dimension of the lattice, B denotes an upper bound for the Euclidean norm of the input basis vectors, and M (k) denotes the time required to multiply two k-bit integers (cf. [NS]). One can safely assume M (k) = O(k 2 ). Since the worst-case running time of the LLL algorithm (and, consequently, of the Fincke-Pohst algorithm) increases as the dimension of the lattice increases, it is not immediately clear that replacing our original approximation lattices with higher-dimensional ones will improve the efficiency of the algorithm. However, because of how m is chosen, an increase in lattice dimension will decrease the expected size of m. So, since m is proportional to the bound B, the running time of the LLL algorithm decreases 74  as m decreases. Moreover, smaller values of m mean smaller bounds are produced by the reduction procedures, which reduces the total number of iterations of the reduction procedure needed. This rough analysis is clearly not definitive, but, according to Smart [Sm], the overall effect of using the (v + r + s − 1)-dimensional lattices rather than (v + r)dimensional is that the computational cost of the pl -reduction procedures is lowered. Though we expect there are numerous improvements and optimizations that can be made in our implementation of the algorithm, we believe the implementation to be generally good. Improving the implementation of the sieving process is likely the most important improvement that could be made in the program since this process appears to be the principle bottleneck in the algorithm in practice (at least in cases when the degree of the equation and the number of primes and fundamental units is not very large).  75  References [ACHP] A. K. Agrawal, J. H. Coates, D. C. Hunt, and A. J. van der Poorten, Elliptic curves of conductor 11, Mathematics of Computation 35 (1980), 991-1002. [BCP] W. Bosma, J. Cannon, and C. Playoust, The Magma algebra system. I. The user language. Journal of Symbolic Computation 24 (1997), no. 3-4, 235-265. http: //magma.maths.usyd.edu.au/magma/ [BD] M. A. Bennett and S. Dahmen, Klein forms and the generalized superelliptic equation, submitted. [BS] Z. I. Borevich and I. R. Shafarevich, Number theory, Academic Press, 1966. [BL] Y. Bugeaud and M. Laurent, Minoration effective de la distance p-adique entre puissances de nombres alg´ebriques (French) [Effective lower bound for the p-adic distance between powers of algebraic numbers], Journal of Number Theory 61 (1996), 311-342. [Ca] J. W. S. Cassels, Local fields, Cambridge University Press, 1986. [Cr] J. Cremona, The elliptic curve database for conductors to 130000, Algorithmic Number Theory : 7th International Symposium, ANTS-VII, Berlin, Germany, July 23-28, 2006, Proceedings, 11-29, Lecture Notes in Computer Science 4076, Springer, 2007. [Coa1] J. H. Coates, An effective p-adic analogue of a theorem of Thue, Acta Arithmetica 15 (1969), 279-305. [Coa2] J. H. Coates, An effective p-adic analogue of a theorem of Thue II: The greatest prime factor of a binary form, Acta Arithmetica 16 (1970), 399-412. [Coh1] H. Cohen, A course in computational algebraic number theory, Springer-Verlag, 1995. [Coh2] H. Cohen, Number theory volume I: tools and diophantine equations, Springer Science + Business Media, LLC, 2007. [FP] U. Fincke and M. Pohst, Improved methods for calculating vectors of short length in a lattice, including a complexity analysis, Mathematics of Computation 44 (1985), no. 170, 463-471. 76  [Ha] H. Hasse, Number theory, Springer-Verlag, 1980. [Ko] N. Koblitz, p-adic numbers, p-adic analysis, and zeta-functions, Springer-Verlag, 1977. [La] M. Laurent, Linear forms in two logarithms and interpolation determinants II, Acta Arithmetica 133 (2008), no. 4, 325-348. [LLL] A.K. Lenstra, H.W. Lenstra Jr., and L. Lovasz, Factoring polynomials with rational coefficients, Mathematische Annalen 261 (1982), 515-534. [Mah] K. Mahler, Zur approximation algebraischer zahlen. I., Mathematische Annalen, 107 (1933), 691-730. [Mat] E. M. Matveev, An explicit lower bound for a homogeneous rational linear form in the logarithms of algebraic numbers. II., Izvestiya: Mathematics, 64 (2000), no. 6, 1217-1269. [Mi1] M. Mignotte, Linear forms in two and three logarithms and interpolation determinants, Diophantine Equations, 151-166, Tata Institute of Fundamental Research Studies in Mathematics 20, Tata Institute of Fundamental Research, 2008. [Mi2] M. Mignotte, A kit on linear forms in three logarithms, preprint. [Na] W. Narkiewicz, Elementary and analytic theory of algebraic numbers, 3rd ed., Springer-Verlag, 2004. [NS] P. Nguyen and D. Stehl´e, An LLL algorithm with quadratic time complexity, SIAM Journal on Computing 39 (2009), no. 3, 874-903. [Sm] N.P. Smart, The algorithmic resolution of diophantine equations, Chapman and Hall, Cambridge University Press, 1998. [St] D. Stehl´e, Floating-point LLL: theoretical and practical aspects, The LLL Algorithm, Survey and Application, Springer-Verlag, 2010. [ST] I. N. Stewart and D. O. Tall, Algebraic number theory, Chapman and Hall, Cambridge University Press, 1979. [SV] V. G. Sprindˇzuk and A.I. Vinogradov, The representation of numbers by binary forms (Russian), Matematicheskie Zametki 3 (1968), 369-376.  77  [SW] D. Stehl´e and M. Watkins, On the extremality of an 80-dimensional lattice, Algorithmic Number Theory: 9th International Symposium, ANTS-IX, Nancy, France, July 19-23, 2010, Proceedings, 340-356, Lecture Notes in Computer Science 6197, Springer, 2010. [TW1] N. Tzanakis and B. M. M. de Weger, Solving a specific Thue-Mahler equation, Mathematics of Computation 57 (1991), no. 196, 779-815. [TW2] N. Tzanakis and B. M. M. de Weger, How to explicitly solve a Thue-Mahler equation, Compositio Mathematica 84 (1992), 223-288. [dW1] B. M. M. de Weger, Algorithms for diophantine equations, CWI Tract No. 65, Centre for Math and Computer Science, Amsterdam, 1989. [dW2] B. M. M. de Weger, On the practical solution of Thue-Mahler equations, an outline, Colloquia Mathematica Societatis J´ anos Bolyai, 51 (1990), 1037-1050. [Yu1] K. Yu, Linear forms in p-adic logarithms II, Compositio Mathematica 74 (1990), 15-113. [Yu2] K. Yu, P -adic logarithmic forms and group varieties III, Forum Mathematicum 19 (2007), 187-280.  78  Appendix: The implementation in Magma function ThueMahlerSolver(c,p,a) //////////////////////////////////////////////////// //Description of Input //////////////////////////////////////////////////// /* c is the (integer) sequence of coefficients of F(x,y). c[i]=c_i from (3). The coefficient c_0 of x^n is not to be entered. It is assumed that c_0=1. It is also assumed that F(x,y) is irreducible. p is the sequence of rational primes. p[i]=p_i from (3) a is the integer a from (3). It is assumed that (a,p_i)=1 for i=1,..,v. For the example equation solved in [TW2], we would use c:=[-23,5,24]; p:=[2,3,5,7]; a:=1; */ /////////////////////////////////////////////// //Description of Output: //////////////////////////////////////////////// /* A list of solutions [X,Y,z_1,...,z_v] of the Thue-Mahler equation */ ////////////////////////////////////////////////////////  79  //Define the n = degree of g(t) and v = number of primes /////////////////////////////////////////////////////// n:=#c;  //degree of F(t,1)=g(t)  v:=#p;  //number of primes  //////////////////////////////////////////////////// //List of Solutions //////////////////////////////////////////////////// Solutions:=[]; //to be filled //SolutionsTest:=[]; //ExceptionalTuplesTest:=[];  ////////////////////////////////////////////// //Define g and compute its discriminant ///////////////////////////////////////////// Zt<t>:=PolynomialRing(Integers()); g:=t^n+c[n]; for i:=1 to n-1 do g:=g+c[i]*t^(n-i); end for; DiscriminantOfg:=Discriminant(g); ////////////////////////////////////////////////// //Define K and compute number field data ////////////////////////////////////////////////// //define K=Q(theta) K<theta>:=NumberField(g); //Compute the ring of integers OK of K OK:=MaximalOrder(K); //Compute an integral basis for K IntegralBasisK:=IntegralBasis(K); 80  //For each element of the integral basis for K, compute its //coefficients on the power basis of K: 1,theta,...,theta^{n-1} CoefficientsOfIntegralBasisElement:=[]; for i:=1 to n do CoefficientsOfIntegralBasisElement[i]:= Eltseq(IntegralBasisK[i]); end for; //s = number of real embeddings, 2t = number of complex //embeddings s,t:=Signature(K); //number of fundamental units r:=s+t-1; //Compute a set of fundamental units and //express them as elements in OK in terms of the integral basis //they are represented by their coefficients on the integral basis U,psi:=UnitGroup(OK); eps:=[]; for i:= 1 to r do eps[i]:=psi(U.(i+1)); end for; eps[s+t]:=psi(U.1); //generator for units of finite order //Compute the divisors of the class number of K DivisorsOfClassNumberOfK:=Divisors(ClassNumber(K)); /////////////////////////////////////////////////////////////////////// /* Compute the splitting field F of g over Q (FFF), the roots of g in F (rootsofginFFF), and the ring of integers of F (OF) */ /////////////////////////////////////////////////////////////////////// 81  FFF,rootsofginFFF:=SplittingField(g); OF:=MaximalOrder(FFF); //////////////////////////////////////////////////////////////////// /* Set precision for real/complex and p-adic computations We want the precision for real/complex computations (realprecision) to be about four time as large as the largest value of Log(C)/Log(10) (the number of decimal digits in C) reduction step (Section 19).  that we expect will occur in the real C will about the size of H_0^(v+r), so we  want to take realprecision \approx 2*(v+r)*Log(H_0)/Log(10).  (We would  be fine if instead of "four times as large" it was just "larger" than. We go four times as large as a safety factor to avoid having to back up and do all the calculations again with an increased precision.) We want to choose the precision for p_i-adic computations (padicprecision[i]) is about four times as large as the largest value of m that we expect will occur in the p_i-adic reduction step (Section 18). m will be of a size that makes p_i^m \approx H_0^(v+r), so we want to take padicprecision[i] \approx 2*(v+r)*Log(H_0)/Log(p[i]).  (We would be  fine if instead of "four times as large" it was just "larger" than.  We  go four times as large as a safety factor to avoid having to back up and do all the calculations again with an increased precision.) We cannot calculate H_0 a priori.  But we know H_0 will be essentially of  the size of that largest of the constants coming from using Yu’s and Matveev’s theorems to bound the relevant linear forms in logarithms. The constant c_2 \cdot \min{ c_3^{\prime}, c_3^{prime}  } from Yu’s  theorem will be bounded by something of the size (16*Exp(1)*Degree(F))^(2*(2+v+r)) * (1+v+r)^3 * Log(Degree(F)*(1+v+r)) * Max(p[1],...,p[v])^(Degree(F)) * (10)^(1+v+r)  82  (see [Yu2] p.190). The constant c_17 from Matveev’s Theorem will be bounded by something of the size 2^(6*(1+v+r)+20) * Degree(F)^(3+v+r) * Log(Degree(F)) * 10^(1+v+r) Here we are assuming that the absolute logarithmic heights involved are <= 10. We set the up a loop so that, if the precisions are not high enough, we back up and start again with more precision. */ //////////////////////////////////////////////////////////////////////// RealPrecisionMultiplier:=1; PadicPrecisionMultiplier:=[]; for i:=1 to v do PadicPrecisionMultiplier[i]:=1; end for; for PrecisionLoopVariable:=1 to 5 do if PrecisionLoopVariable eq 5 then print("Something is wrong. The required precision for the computation seems to be too large."); break PrecisionLoopVariable; end if; H0estimate:=Max([ (16*Exp(1)*Degree(FFF))^(2*(2+v+r)) * (1+v+r)^3 * Log(Degree(FFF)*(1+v+r)) * Max(p)^(Degree(FFF)) * (10)^(1+v+r), 2^(6*(1+v+r)+20) * Degree(FFF)^(3+v+r) * Log(Degree(FFF)) * 10^(1+v+r) ]);  83  realprecision:=4*Ceiling((v+r)*Log(H0estimate)/Log(10)); realprecision:=realprecision*RealPrecisionMultiplier; padicprecision:=[]; for i:=1 to v do padicprecision[i]:=4*Ceiling((v+r)*Log(H0estimate)/Log(p[i])); padicprecision[i]:=padicprecision[i]*PadicPrecisionMultiplier[i]; end for; SetDefaultRealField(RealField(realprecision)); PI:=Pi(RealField()); /* print("padicprecision"); padicprecision; print("realprecision"); realprecision; */  //////////////////////////////////////////////////////////////////////// /* For each prime p[i], compute the primes of OK dividing p[i] (pp[i][j]), their number (m[i]), their ramification indices (e[i][j]), and their residue degrees (f[i][j]). For each pp[i][j] with e[i][j]=f[i][j]=1 (i.e. for each unramified degree one prime ideal above p[i]), compute the least positive integer h[i][j] such that pp[i][j]^h[i][j] is principal and the generator pi[i][j] of pp[i][j]^h[i][j]. Also store the indices j of the unramified degree one primes pp[i][j] above p[i]. */ ///////////////////////////////////////////////////////////////////////// 84  pp:=[]; m:=[]; e:=[]; f:=[]; IndicesOfUnramifiedDegreeOnePrimesAbovep:=[]; h:=[]; pi:=[]; DecompositionOfp:=[]; for i:=1 to v do pp[i]:=[]; e[i]:=[]; f[i]:=[]; IndicesOfUnramifiedDegreeOnePrimesAbovep[i]:=[]; h[i]:=[]; pi[i]:=[]; DecompositionOfp[i]:=Decomposition(OK,p[i]); m[i]:=#DecompositionOfp[i]; //number of distinct prime factors of p[i] for j:=1 to m[i] do pp[i][j]:=DecompositionOfp[i][j][1]; e[i][j]:=DecompositionOfp[i][j][2]; f[i][j]:=InertiaDegree(pp[i][j]); if e[i][j]*f[i][j] eq 1 then Append(~IndicesOfUnramifiedDegreeOnePrimesAbovep[i],j); for k:=1 to #DivisorsOfClassNumberOfK do if IsPrincipal(pp[i][j]^DivisorsOfClassNumberOfK[k]) then h[i][j]:=DivisorsOfClassNumberOfK[k]; temp,pi[i][j]:=IsPrincipal(pp[i][j]^DivisorsOfClassNumberOfK[k]); end if; end for; else h[i][j]:=0; pi[i][j]:=eps[s+t];  //initialization, never used //initialization, never used  end if; end for; //end j loop 85  end for; //end i loop ///////////////////////////////////////////////// /* Compute completion of K at each pp[i][j] (Kpp[i][j]) and the embedding of K into Kpp[i][j] (mKpp[i][j]).  Also, for each pp[i][j], compute the  corresponding factor of g(t) in \QQ_{p[i]}[t] (gp[i][j]) gp[i][j] = g_j(t) from Section 3 with p=p_i */ //////////////////////////////////////////////// Kpp:=[]; mKpp:=[]; gp:=[**]; for i:=1 to v do Kpp[i]:=[]; mKpp[i]:=[**]; gp[i]:=[]; for j:=1 to m[i] do //m[i]:=number of distinct prime factors of p[i] Kpp[i][j], mKpp[i][j]:=Completion(K,pp[i][j] : Precision :=padicprecision[i] ); gp[i][j]:=MinimalPolynomial( mKpp[i][j](theta), PrimeField(Kpp[i][j])); end for; end for; /* LocalFactorization(PolynomialRing(pAdicRing(p[1] : Precision:=20)) ! g : Ideals:=true); */ ////////////////////////////////////////////////////////////////////// /* For each p[i], compute the completion FFFppF of FFF at a prime ideal ppF of OF.  Also compute the embedding of FFF into FFFppF (mFFFppF).  Note FFFppF contains the splitting field of g over Q_{p[i]}.  86  MAGMA currently does not support the direct computation of the splitting field of g over Q_{p[i]}.  The function that purports to do this fails  for p[i] that ramify in the K. Note that since F/Q is Galois, every prime ideal of OF above p[i] has the same ramification index and residue degree */ ///////////////////////////////////////////////////////////////////// ppF:=[];  //ppF[i] is a prime of FFF above p[i] selected essentially //arbitrarily  eF:=[];  //eF[i] is the ramification index of ppF over Q  fF:=[];  //fF[i] is the residue degree of ppF over Q  FFFppF:=[]; mFFFppF:=[**]; SS:=[];  //SS[i] is the degree of FFFppF[i] over Q_p[i]  DecompositionInFFFOfp:=[]; for i:=1 to v do DecompositionInFFFOfp[i]:=Decomposition(OF,p[i]); eF[i]:=DecompositionInFFFOfp[i][1][2]; fF[i]:=InertiaDegree(DecompositionInFFFOfp[i][1][1]); ppF[i]:=DecompositionInFFFOfp[i][1][1]; FFFppF[i],mFFFppF[i]:=Completion(FFF,ppF[i]:Precision:=padicprecision[i]); SS[i]:=AbsoluteDegree(FFFppF[i]); end for;  //end i loop  //////////////////////////////////////////////////////////////// /* Magma’s Completion() function will make FFFppF[l] as one the following types of field extensions: 1. an unramified extension over the p_l-adic field 2. a totally ramified extension over a p_l-adic field 3. an unramified extension over an unramified extension over a p_l-adic field 87  4. a totally ramified extension over an unramified extension over a p-adic field We will later want to find the coefficients of elements of FFFppF[l] on the (canonical) power basis of FFFppF[l] over Q_{p_l}.  For this, it will  be important to know what type of extension FFFppF[l] is.  The variable  FFFppFType will indicate this. The first two types are easy to identify and they come as simple extensions, which will let us use MAGMA built-in function for finding the coefficients of elements on the power basis. The third type seems to be a quirk of Magma.  The top extension always  has degree 1 relative to the intermediate extension.  Moreover, the  minimal polynomial of the top extension over the intermediate extension is always x.  Finding the coefficients of elements on the power basis  will be only slighlty harder than in cases 1. and 2. For the fourth type, the top extension will always have relative degree greater than one.  We will have to work a bit harder to find coefficients  of elements here. First we find an element generator[l] that generates FFFppF[l] over Q_{p_l}.  Then we construct a matrix A[l] containing the information  necessary to find the coefficients of elements of FFppF[l] on the basis 1,generator[l],...,generator[l]^(d3 - 1), where d3 = degree of FFFpFF[l] over Q_{p_l}.  We will actually need the inverse of this matrix, so we  take it now. More explictly, we construct A[l] as follows. Let \alpha be the generator of FFFpFF[l] over its coefficient field Let \beta be the generator of the coefficient field of FFFpFF[l] over Q_{p_l} d1 = degree of FFFpFF[l] over its coefficient field d2 = degree of the coefficient field over Q_{p_l} 88  d3 = d1*d2 = degree of FFFpFF[l] over Q_{p_l} Let c_{ijk} be the numbers in Q_{p_l} such that generator^{k-1} = sum_{i,j} c_{ijk} \alpha^{i-1} \beta^{j-1} Here i ranges from 1 to d1, j ranges from 1 to d2, k ranges from 1 to d3. A[l] = c_{1 1 1} ... c_{1 1 d3} .  .  .  .  .  .  c_{1 d2 1} ... c_{1 d2 d3} .  .  .  .  .  .  c_{d1 1 1} ... c_{d1 1 d3} .  .  .  .  .  .  c_{d1 d2 1} ... c_{d1 d2 d3}  We also define here u_l = (1/2) * \ord_{p_l}(Discr G(t)) from Section 8 u[l]:=(1/2)*Valuation(Discriminant(DefiningPolynomial( CoefficientField(FFFppF[l])))); */ //////////////////////////////////////////////////////////////// FFFppFType:=[]; generator:=[**]; Ainverse:=[]; d1:=[]; d2:=[]; d3:=[]; u:=[RationalField() | ]; for l:=1 to v do 89  FFFppFType[l]:=5; generator[l]:=FFFppF[l].1;  //initialize //initialize, only used in case //FFFppFType[l]=4  Ainverse[l]:=1;  //initialize  d1[l]:=Degree(FFFppF[l],CoefficientField(FFFppF[l])); d2[l]:=Degree(CoefficientField(FFFppF[l]),PrimeField(FFFppF[l])); d3[l]:=Degree(FFFppF[l],PrimeField(FFFppF[l])); u[l]:=1; if AbsoluteRamificationIndex(FFFppF[l]) eq 1 then FFFppFType[l]:=1; u[l]:=(1/2)*Valuation(Discriminant(DefiningPolynomial(FFFppF[l]))); if Valuation(FFFppF[l].1) lt 0 then print("Error. Generator has negative valuation.  Results invalid. l="); l; end if;  end if; if AbsoluteInertiaDegree(FFFppF[l]) eq 1 then FFFppFType[l]:=2; /*FFFppF[l]; DefiningPolynomial(FFFppF[l]); Discriminant(DefiningPolynomial(FFFppF[l])); Parent((1/2)*Valuation(Discriminant(DefiningPolynomial(FFFppF[l])))); (1/2)*Valuation(Discriminant(DefiningPolynomial(FFFppF[l])));*/ u[l]:=(1/2)*Valuation(Discriminant(DefiningPolynomial(FFFppF[l]))); if Valuation(FFFppF[l].1) lt 0 then print("Error. Generator has negative valuation.  Results invalid. l="); l; end if;  end if; if AbsoluteInertiaDegree(FFFppF[l]) gt 1 and d1[l] eq 1 then FFFppFType[l]:=3; u[l]:=(1/2)*Valuation(Discriminant(DefiningPolynomial( CoefficientField(FFFppF[l])))); if Valuation(CoefficientField(FFFppF[l]).1) lt 0 then print("Error. Generator has negative valuation.  Results invalid. l="); l; end if;  end if; 90  if d1[l] gt 1 and d2[l] gt 1 then FFFppFType[l]:=4; k:=1; while true do generator[l] := k*FFFppF[l].1 + (FFFppF[l] ! CoefficientField(FFFppF[l]).1); if Degree(MinimalPolynomial(generator[l],PrimeField(FFFppF[l]))) eq d3[l] then break; end if; k +:= 1; end while; u[l]:=(1/2)*Valuation(Discriminant(MinimalPolynomial( generator[l],PrimeField(FFFppF[l])))); if Valuation(generator[l]) lt 0 then print("Error. Generator has negative valuation.  Results invalid. l="); l; end if;  //Note: d3[l]:=d1[l]*d2[l]; A:=ZeroMatrix( PrimeField(FFFppF[l]), d3[l], d3[l]); //initialize temp1:=Coefficients(generator[l]); //initialize temp2:=Coefficients(temp1[1]); //initialize for k:=1 to d3[1] do temp1:=Coefficients(generator[l]^(k-1)); for i:=1 to d1[1] do temp2:=Coefficients(temp1[i]); for j:=1 to d2[1] do A[(i-1)*d2 + j,k]:=temp2[j]; end for; end for; end for; 91  Ainverse[l]:=A^(-1); end if; if FFFppFType[l] eq 5 then print("Error in FFFppFType. l:"); l; end if; end for; //end l loop  ///////////////////////////////////////////////////////////////////////// /* Define a function to compute the coefficients of an element x in FFFppF[l] */ ///////////////////////////////////////////////////////////////////////// function GetCoefficients(x,l) /* Input: l in {1,...,v}, x = an element of FFFppF[l] Output:  The coefficients of x on the basis power basis for FFFppF[l]  over Q_{p_l}. */ output:=Coefficients(x); if FFFppFType[l] eq 3 then output:=Coefficients(Coefficient(x,1)); end if; if FFFppFType[l] eq 4 then B:=ZeroMatrix( PrimeField(FFFppF[l]), d3, 1); temp1:=Coefficients(x); temp2:=Coefficients(temp1[1]); //initialize for i:=1 to d1[l] do temp2:=Coefficients(temp1[i]); for j:=1 to d2[l] do B[(i-1)*d2[l] + j,1]:=temp2[j]; end for; end for; C:=Ainverse[l]*B; output:=[]; for i:=1 to d3[l] do 92  output[i]:=C[i][1]; end for; end if; return output; end function;  ////////////////////////////////////////////////////////////////////// /* thetap[l][i][j]:= theta_i^{(j)} from Section 3 with p=p_l */ ////////////////////////////////////////////////////////////////////// thetap:=[]; for l:=1 to v do thetap[l]:=[]; for i:=1 to m[l] do thetap[l][i]:=[**]; temp:=Roots(gp[l][i],FFFppF[l]); for j:=1 to #temp do  //#temp = degree of gp[l][i] = //  = e[l][i]*f[l][i]  thetap[l][i][j]:=temp[j][1]; end for; end for; end for; /////////////////////////////////////////////////////////////// /* ImageOfIntegralBasisElementp[L][i][j][k] = image of the kth element in the integral basis for K under the embedding of K into \overline{\QQ_{p_L}} defined by the map theta --> thetap[L][i][j] */ /////////////////////////////////////////////////////////////// ImageOfIntegralBasisElementp:=[]; for l:=1 to v do 93  ImageOfIntegralBasisElementp[l]:=[]; for i:=1 to m[l] do ImageOfIntegralBasisElementp[l][i]:=[]; for j:=1 to e[l][i]*f[l][i] do ImageOfIntegralBasisElementp[l][i][j]:=[**]; for k:=1 to n do ImageOfIntegralBasisElementp[l][i][j][k]:=0; for ii:= 1 to n do ImageOfIntegralBasisElementp[l][i][j][k]:= ImageOfIntegralBasisElementp[l][i][j][k] + CoefficientsOfIntegralBasisElement[k][ii]*thetap[l][i][j]^(ii-1); end for; //ii end for; //k end for; //j end for; //i end for; //l //////////////////////////////////////////////////////////////////////// /* ImageOfpip[L][k][l][i][j] := the image of pi[L][k] under the embedding of K into \overline{\QQ_{p_l}} defined by the map theta --> thetap[l][i][j]. Recall pi[L][k] is the generator of pp_{Lk}^h[L][k]. ImageOfepsp[L][l][i][j] := the image of eps[L] under the embedding of K into \overline{\QQ_{p_l}} defined by the map theta --> thetap[l][i][j]. */ /////////////////////////////////////////////////////////////////////// ImageOfpip:=[]; for L:=1 to v do ImageOfpip[L]:=[]; for k:=1 to m[L] do if e[L][k]*f[L][k] eq 1 then ImageOfpip[L][k]:=[]; for l:=1 to v do ImageOfpip[L][k][l]:=[]; 94  for i:=1 to m[l] do ImageOfpip[L][k][l][i]:=[**]; for j:=1 to e[l][i]*f[l][i] do ImageOfpip[L][k][l][i][j]:=0; for ii:= 1 to n do ImageOfpip[L][k][l][i][j]:=ImageOfpip[L][k][l][i][j] + pi[L][k][ii]*ImageOfIntegralBasisElementp[l][i][j][ii]; end for; //ii end for; //j end for; //i end for; //l else ImageOfpip[L][k]:=[[[*0*]]]; end if; end for; //k end for; //L ImageOfepsp:=[]; for L:=1 to r do ImageOfepsp[L]:=[]; for l:=1 to v do ImageOfepsp[L][l]:=[]; for i:=1 to m[l] do ImageOfepsp[L][l][i]:=[**]; for j:=1 to e[l][i]*f[l][i] do ImageOfepsp[L][l][i][j]:=0; for ii:= 1 to n do ImageOfepsp[L][l][i][j]:=ImageOfepsp[L][l][i][j] + eps[L][ii]*ImageOfIntegralBasisElementp[l][i][j][ii]; end for; //ii end for; //j end for; //i end for; //l end for; //L  95  //////////////////////////////////////////////////////////////////////// /* thetaC:= the conjugates of theta as elements in the field of complex numbers = the roots of the minimal polynomial of theta (i.e. of g) in the field of complex numbers */ ///////////////////////////////////////////////////////////////////////// thetaC:=Conjugates(theta); /////////////////////////////////////////////////////////////// /* ImageOfIntegralBasisElementC[i][k] = image of the kth element in the integral basis for K under the embedding of K into \CC defined by the map theta --> thetaC[i] */ /////////////////////////////////////////////////////////////// ImageOfIntegralBasisElementC:=[]; for i:=1 to n do ImageOfIntegralBasisElementC[i]:=[**]; for k:=1 to n do ImageOfIntegralBasisElementC[i][k]:=0; for ii:= 1 to n do ImageOfIntegralBasisElementC[i][k]:=ImageOfIntegralBasisElementC[i][k] + CoefficientsOfIntegralBasisElement[k][ii]*thetaC[i]^(ii-1); end for; //ii end for; //k end for; //i //////////////////////////////////////////////////////////////////////// /* ImageOfpiC[L][k][i] := the image of pi[L][k] under the embedding of K into \CC defined by the map theta --> thetaC[i].  Recall pi[L][k] is the  generator of pp_{Lk}^h[L][k]. 96  ImageOfepsC[L][i] := the image of eps[L] under the embedding of K into \CC defined by the map theta --> thetaC[i]. */ //////////////////////////////////////////////////////////////////////// ImageOfpiC:=[]; for L:=1 to v do ImageOfpiC[L]:=[]; for k:=1 to m[L] do if e[L][k]*f[L][k] eq 1 then ImageOfpiC[L][k]:=[**]; for i:=1 to n do ImageOfpiC[L][k][i]:=0; for ii:= 1 to n do ImageOfpiC[L][k][i]:=ImageOfpiC[L][k][i] + pi[L][k][ii]*ImageOfIntegralBasisElementC[i][ii]; end for; //ii end for; //i else ImageOfpiC[L][k]:=[*0*]; end if; end for; //k end for;  //L  ImageOfepsC:=[]; for L:=1 to r do ImageOfepsC[L]:=[**]; for i:=1 to n do ImageOfepsC[L][i]:=0; for ii:= 1 to n do ImageOfepsC[L][i]:=ImageOfepsC[L][i] + eps[L][ii]*ImageOfIntegralBasisElementC[i][ii]; end for; //ii end for; //i 97  end for; //L  /////////////////////////////////////////////////////////////////////// /* Recall F = the splitting field of g over Q thetaF:= the conjugates of theta as elements in F = the roots of the minimal polynomial of theta (i.e. of g) in F */ ////////////////////////////////////////////////////////////////////// thetaF:=rootsofginFFF; /////////////////////////////////////////////////////////////// /* ImageOfIntegralBasisElementF[i][k] = image of the kth element in the integral basis for K under the embedding of K into F defined by the map theta --> thetaF[i] */ /////////////////////////////////////////////////////////////// ImageOfIntegralBasisElementF:=[]; for i:=1 to n do ImageOfIntegralBasisElementF[i]:=[**]; for k:=1 to n do ImageOfIntegralBasisElementF[i][k]:=0; for ii:= 1 to n do ImageOfIntegralBasisElementF[i][k]:=ImageOfIntegralBasisElementF[i][k] + CoefficientsOfIntegralBasisElement[k][ii]*thetaF[i]^(ii-1); end for; //ii end for; //k end for; //i //////////////////////////////////////////////////////////////////////// 98  /* ImageOfpiF[L][k][i] := the image of pi[L][k] under the embedding of K into F defined by the map theta --> thetaF[i]. Recall pi[L][k] is the generator of pp_{Lk}^h[L][k]. ImageOfepsF[L][i] := the image of eps[L] under the embedding of K into F defined by the map theta --> thetaF[i]. */ /////////////////////////////////////////////////////////////////////// ImageOfpiF:=[]; for L:=1 to v do ImageOfpiF[L]:=[]; for k:=1 to m[L] do if e[L][k]*f[L][k] eq 1 then ImageOfpiF[L][k]:=[**]; for i:=1 to n do ImageOfpiF[L][k][i]:=0; for ii:= 1 to n do ImageOfpiF[L][k][i]:=ImageOfpiF[L][k][i] + pi[L][k][ii]*ImageOfIntegralBasisElementF[i][ii]; end for; //ii end for; //i else ImageOfpiF[L][k]:=[*0*]; end if; end for; //k end for;  //L  ImageOfepsF:=[]; for L:=1 to r do ImageOfepsF[L]:=[**]; for i:=1 to n do ImageOfepsF[L][i]:=0; for ii:= 1 to n do 99  ImageOfepsF[L][i]:=ImageOfepsF[L][i] + eps[L][ii]*ImageOfIntegralBasisElementF[i][ii]; end for; //ii end for; //i end for; //L  ///////////////////////////////////////////////////////////////////////// /* Compute the constant constant c10 = c_{10} from Section 12 Note: If kappa = {k_1,...,k_r} with 1 <= k_1 < ... < k_r <= s+t, then there is a unique index k* in {1,...,s+t}-{k_1,...,k_r} and U_kappa from Section 12 is equal to the matrix formed by starting with the r by s+t matrix. U = (log|\eps_j^{(i)}|) and removing the k*th row. We use this equivalent definition of U_kappa below. */ ///////////////////////////////////////////////////////////////////////// //Function to compute maximum absolute row sum of an r by r matrix U function MaximumAbsoluteRowSum(U,r) max:=0; for i:=1 to r do sum:=0; for j:=1 to r do sum:=sum+Abs(U[i][j]); end for; if sum gt max then max:=sum; end if; end for; return max; end function;  100  U:=ZeroMatrix(ComplexField(),s+t,r); for i:=1 to s+t do for j:=1 to r do U[i][j]:=Log(Abs(ImageOfepsC[j][i])); end for; end for; currentmin:=MaximumAbsoluteRowSum( RemoveRow(U,1)^(-1),r ); for skippedindex:=1 to s+t do  //skipped index = k*  potentialmin:=MaximumAbsoluteRowSum( RemoveRow(U,skippedindex)^(-1),r ); if potentialmin lt currentmin then currentmin:=potentialmin; end if; end for; c10:=1/currentmin;  //Now we go essentially in the order of the thesis starting at Section 6. /////////////////////////////////////////////////////////////////// //Apply Prime Ideal Removing Lemma /////////////////////////////////////////////////////////////////// /* The elements of ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] will be of the form [[k],aaa]. If k <= m[L], then k has the meaning that pp[L][k] is the unconstrained prime above p[L] (pp[L][k] must have e[L][k]=f[L][k]=1). If k = m[L]+1, there is no prime above p[L] with ramification index and residue degree equal to one, hence no unconstrained prime above p[L]. In either case, aaa is a tuple of nonnegative integers such that that PowerProduct(pp[L],aaa) is the factor of bb=\mathfrak{b} consisting of 101  primes above p[L]. Note aaa[k]=0 if k <= m[L]. */ ///////////////////////////////////////////////////////////////////////  ////////////////////////////////////////////////////////////////////// /* Define the procedures we need */ /////////////////////////////////////////////////////////////////////// procedure BuildListOfValidTuplesWhenppLkIsTheUnconstrainedPrimeAbovepL( i,L,k,~aaa,~D,~m,~CC,~LIST) for l:=0 to D[i] do aaa[i]:=l; if i eq m[L] then //aaa[k]:=0; Include(~LIST,[[k],aaa]); else for j:=i+1 to m[L] do if aaa[i] gt CC[i][j] then D[j]:=Min(D[j],CC[i][j]); end if; end for; BuildListOfValidTuplesWhenppLkIsTheUnconstrainedPrimeAbovepL( i+1,L,k,~aaa,~D,~m,~CC,~LIST); end if; end for; end procedure; procedure BuildListOfValidTuplesWhenNoUnramifiedDegreeOnePrimesAbovepL( i,L,k,~aaa,~D,~m,~CC,~LIST) for l:=0 to D[i] do aaa[i]:=l; if i eq m[L] then 102  Include(~LIST,[[k],aaa]); else for j:=i+1 to m[L] do if aaa[i] gt CC[i][j] then D[j]:=Min(D[j],CC[i][j]); end if; end for; BuildListOfValidTuplesWhenNoUnramifiedDegreeOnePrimesAbovepL( i+1,L,k,~aaa,~D,~m,~CC,~LIST); end if; end for; end procedure; ////////////////////////////////////////////////////////////////////// //The algorithm ///////////////////////////////////////////////////////////////////// ListOfTuplesOfExponentsForPrimesDividingbbAbovep:=[**]; for L:=1 to v do ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]:=[];  //////////////////////////////////////////////////////////// /* CC[i][j]:= \max\cbr{e_i,e_j} \cdot \min_{k,l} \cbr{ord_p(theta_{i}^{(k)} - theta_{j}^{(l)})} */ ///////////////////////////////////////////////////////////// CC:=[]; for i:=1 to m[L] do CC[i]:=[]; for j:=1 to i-1 do temp:=[]; for k:=1 to #thetap[L][i] do for l:=1 to #thetap[L][j] do Append(~temp, Valuation( thetap[L][i][k] - thetap[L][j][l] )); end for; end for; 103  CC[i][j]:=Max([e[L][i],e[L][j]])*Min(temp); end for; end for; for i:=1 to m[L] do if e[L][i]*f[L][i] eq 1 then CC[i][i]:=2^15; //placeholder, never used else temp:=[]; for k:=1 to #thetap[L][i] do for l:=k+1 to #thetap[L][i] do Append(~temp,Valuation( thetap[L][i][k] - thetap[L][i][l] ) ); end for; end for; CC[i][i]:=e[L][i]*Min(temp); end if; end for; for i:=1 to m[L] do for j:=i+1 to m[L] do CC[i][j]:=CC[j][i]; end for; end for; DD:=Floor((1/2)*Max(e[L])*Valuation(DiscriminantOfg, p[L])); if m[L] gt 1 then DD:=0; for i:=1 to m[L] do for j:=i+1 to m[L] do if CC[i][j] gt DD then DD:=CC[i][j]; end if; end for; end for; end if; /////////////////////////////////////////////////////// 104  /* For each unramified degree 1 prime pp[L][k] above p[L], list all valid tuples assuming pp[L][k] is the unconstrained prime ideal above p[L] dividing (x-y\theta). The assumption means that, for i=1,...,m[L],i \neq k, we assume the exponent of the prime ideal pp[L][i] above p[L] in the factorization of (x-y\theta) is \leq (1/2)*max(e[L][1],...,e[L][m[L]])*ord_p(D_g).  We  assume nothing about the exponent ord_pp[L][k](x-y\theta) of pp[L][k] in the factorization of (x-y\theta). For i=1,...,m[L],i \neq k, D[i] is an upper bound on the exponent of the prime ideal pp[L][i] above p[L] in the factorization of bb=\mathfrak{b} The exponent of pp[L][k] in the factorization of (x-y\theta) is ord_pp[L][k](x-y\theta) (obviously). Suppose A < B.  The valid tuples aaa  when ord_pp[L][k](x-y\theta) = B are a subset of the valid tuples aaa when ord_pp[L][k](x-y\theta) = A.  So we only need to consider  ord_pp[L][k](x-y\theta) <= DD+1 to find all valid tuples in when ord_pp[L][k](x-y\theta) >= DD+1 and when ord_pp[L][k](x-y\theta) <= DD. Hence the definition of D[k] below. */ /////////////////////////////////////////////////////// for kk:=1 to #IndicesOfUnramifiedDegreeOnePrimesAbovep[L] do k:=IndicesOfUnramifiedDegreeOnePrimesAbovep[L][kk]; //k will go through all the indices of primes ideals above p=p[L] with //e_i=f_i=1 D:=[]; for i:=1 to k-1 do if e[L][i]*f[L][i] eq 1 then D[i]:=DD; else 105  D[i]:=Min(CC[i][i],DD); end if; end for; D[k]:=DD+1; for i:=k+1 to m[L] do if e[L][i]*f[L][i] eq 1 then D[i]:=DD; else D[i]:=Min(CC[i][i],DD); end if; end for; /* Populate ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] assuming pp[L][k]is the unconstrained prime ideal above p[L] dividing (x-y\theta) */ aaa:=[]; BuildListOfValidTuplesWhenppLkIsTheUnconstrainedPrimeAbovepL( 1,L,k,~aaa,~D,~m,~CC, ~ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]);  /* Remove redundant tuples from ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] */ CopyOfListOfTuplesOfExponentsForPrimesDividingbbAbovepL:= ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]; i1:=1; while i1 le #CopyOfListOfTuplesOfExponentsForPrimesDividingbbAbovepL do bbb:=CopyOfListOfTuplesOfExponentsForPrimesDividingbbAbovepL[i1]; if bbb[1][1] ne k then i1:=i1+1; continue; end if; IndexOfTupleToRemove:=-1; 106  for i2:=1 to #ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] do ccc:=ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i2]; if ccc[1][1] ne k then continue i2; end if; for i:=1 to k-1 do if bbb[2][i] ne ccc[2][i] then continue i2; end if; end for; //end i loop for i:=k+1 to #bbb[2] do if bbb[2][i] ne ccc[2][i] then continue i2; end if; end for; //end i loop if bbb[2][k] le ccc[2][k] then continue i2; end if; //know we know that bbb covers ccc IndexOfTupleToRemove:=i2; break i2; end for; if IndexOfTupleToRemove ne -1 then Remove(~ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L], IndexOfTupleToRemove); else i1:=i1+1; end if; end while; /* Done removing tuples */  end for; //end kk loop  /* Remove more redundant tuples from 107  ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] */ CopyOfListOfTuplesOfExponentsForPrimesDividingbbAbovepL:= ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]; i1:=1; while i1 le #CopyOfListOfTuplesOfExponentsForPrimesDividingbbAbovepL do bbb:=CopyOfListOfTuplesOfExponentsForPrimesDividingbbAbovepL[i1]; if bbb[2][bbb[1][1]] ne DD+1 then i1:=i1+1; continue; end if; IndexOfTupleToRemove:=-1; for i2:=1 to #ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] do ccc:=ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i2]; if ccc[2][ccc[1][1]] eq DD+1 then continue i2; end if; //now we know ccc[2][ccc[1][1]] le DD for i:=1 to bbb[1][1]-1 do if bbb[2][i] ne ccc[2][i] then continue i2; end if; end for; for i:=bbb[1][1]+1 to #bbb[2] do if bbb[2][i] ne ccc[2][i] then continue i2; end if; end for; //know we know that bbb covers ccc IndexOfTupleToRemove:=i2; break i2; end for; if IndexOfTupleToRemove ne -1 then Remove(~ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L], IndexOfTupleToRemove); else i1:=i1+1; end if; end while; /* Go through and set aaa[k]=0 for each [[k],aaa] in 108  ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] */ for i1:=1 to #ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] do ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i1][2][ ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i1][1][1] ]:=0; end for;  //////////////////////////////////////////////////////////////////////// /* List all valid tuples in the case there are no unramified degree one primes above p[L]. For i=1,...,m[L], D[i] is an upper bound on the exponent of the prime ideal pp[L][i] above p[L] in the factorization of bb=\mathfrak{b} Should remove p[L] from consideration in certain things below. */ ///////////////////////////////////////////////////////////////////////// if #IndicesOfUnramifiedDegreeOnePrimesAbovep[L] eq 0 then k:=m[L]+1; D:=[]; for i:=1 to m[L] do if e[L][i]*f[L][i] eq 1 then D[i]:=DD; else 109  D[i]:=Min(CC[i][i],DD); end if; end for; //Populate ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] aaa:=[]; BuildListOfValidTuplesWhenNoUnramifiedDegreeOnePrimesAbovepL( 1,L,k,~aaa,~D,~m,~CC, ~ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]); end if;  ////////////////////////////////////////////////////////////// end for; //end L loop //////////////////////////////////////////////////////////// //END Application of Prime Ideal Removing Lemma //////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// //Build ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep ///////////////////////////////////////////////////////// /* For each p[L], if there are unramifed degree one prime ideals of OK above p[L], we augment ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] by taking a given choice of unbounded prime p[L][k] and allowing for all the possible values of the parameter s_{Lk}=s[L][k], which are 0,...,h[L][k]-1 (cf. Section 6) More precisely, for L = 1,...,v we do the following: For each element [[k],aaa] of ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L], we form the elements [[k],aaa,[0]],...,[[k],aaa,[h[L][k]-1]] and adjoin 110  them to a new list ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]. If there are no unramifed degree one prime ideals of OK above p[L], then for each element [[k],aaa] of ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L], we form the element [[k],aaa,0] and adjoin them to ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]. As a minor optimization, all this could be done as part of building ListOfTuplesOfExponentsForPrimesDividingbbAbovep. */ ///////////////////////////////////////////////////////// ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep:=[**]; for L:=1 to v do ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[L]:=[]; for i:=1 to #ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L] do k:=ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i][1][1]; if k ne m[L]+1 then for s:=0 to h[L][k]-1 do Append(~ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[L], Append(ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i],[s])); end for; else //k eq m[L]+1 Append(~ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[L], Append(ListOfTuplesOfExponentsForPrimesDividingbbAbovep[L][i],[0])); end if; end for; end for; delete ListOfTuplesOfExponentsForPrimesDividingbbAbovep; //////////////////////////////////////////////////////////////////////// /* Compute 111  ListOfIdealsOfNorma = list containing a representation of each ideal in OK having norm a. The representation is such that the ideal corresponding to ListIdealsOfNorma[i]ideals is PowerProduct(pI,ListIdealsOfNorma[i]), where pI is the sequence of the prime ideals of OK that divide a. We follow the strategy layed out in the Example on p.125 of [ST] */ //////////////////////////////////////////////////////////////////////// procedure BuildListOfIdealsOfNorma(k,~bbb,~epI,~NpI,~ListOfIdealsOfNorma) for j:=0 to epI[k] do bbb[k]:=j; if k eq #epI then prod:=1; for i:=1 to #epI do prod:=prod*NpI[i]^bbb[i]; end for; if prod eq a or prod eq -a then Append(~ListOfIdealsOfNorma,bbb); end if; else BuildListOfIdealsOfNorma(k+1,~bbb,~epI,~NpI,~ListOfIdealsOfNorma); end if; end for; end procedure; ListOfIdealsOfNorma:=[]; if a eq 1 or a eq -1 then pI:=[ideal<OK|1>]; ListOfIdealsOfNorma:=[[1]]; else //I = ideal<OK|a> = principal ideal generated by a FI:=Factorization(ideal<OK|a>); pI:=[]; epI:=[]; NpI:=[]; 112  for i:=1 to #FI do pI[i]:=FI[i][1]; //ith prime ideal in the factorization of I epI[i]:=FI[i][2]; //ramification index of pI[i] NpI[i]:=Norm(FI[i][1]); end for; bbb:=[]; BuildListOfIdealsOfNorma(1,~bbb,~epI,~NpI,~ListOfIdealsOfNorma); end if;  ///////////////////////////////////////////////// /* Form the list of all units of finite order \zeta in OK (i.e, the list of all roots of unity \zeta in OK) with the understanding that we include only one of \zeta and -\zeta. */ //////////////////////////////////////////////////// ListOfUnitsOfFiniteOrder:=[eps[s+t]]; zeta:=eps[s+t]^2; while(zeta ne eps[s+t]) do Append(~ListOfUnitsOfFiniteOrder,zeta); zeta:=zeta*eps[s+t]; end while; CopyOfListOfUnitsOfFiniteOrder:=ListOfUnitsOfFiniteOrder; NumberOfUnitsOfFiniteOrder:=#ListOfUnitsOfFiniteOrder; for i:=1 to NumberOfUnitsOfFiniteOrder do if CopyOfListOfUnitsOfFiniteOrder[i] in ListOfUnitsOfFiniteOrder and -CopyOfListOfUnitsOfFiniteOrder[i] in ListOfUnitsOfFiniteOrder then Exclude(~ListOfUnitsOfFiniteOrder,-CopyOfListOfUnitsOfFiniteOrder[i]); end if; end for; delete CopyOfListOfUnitsOfFiniteOrder; delete NumberOfUnitsOfFiniteOrder;  113  /* T:=TorsionUnitGroup(K); a:=[]; for u in T do Append(~a,u); end for; a; */ ///////////////////////////////////////////////////////////////////////// /* Construct ListOfCases = the list of all cases of the factorized Thue-Mahler equation (11) that we need to solve. Each element in ListOfCases will be a sequence.  Consider ListOfCases[i].  For L = 1 to v, ListOfCases[i][L] is of the form [[k],aaa,[s]].  The  meaning here is that pp[L][k] is the unbounded prime above p[L], PowerProduct(pp[L],aaa) is the factor of bb consisting of primes above pp[L] and s is the value of the parameter s_{kl}. ListOfCases[i][v+1] has the meaning that the value of the parameter aa is PowerProduct(pI,ListOfCases[i][v+1]). Finally, ListOfCases[i][v+2] is the value of the parameter \zeta */ ///////////////////////////////////////////////////////////////////////// procedure BuildListOfCases(L,~bbb,~LIST,~ListOfCases) for i:=1 to #LIST[L] do bbb[L]:=i; if L eq v+2 then temp:=[**]; for j:=1 to v+2 do temp[j]:=LIST[j][bbb[j]]; end for; 114  Append(~ListOfCases,temp); else BuildListOfCases(L+1,~bbb,~LIST,~ListOfCases); end if; end for; end procedure; ////////////////////////////////////////////////////////////// //preprocessing ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[v+1]:= ListOfIdealsOfNorma; ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep[v+2]:= ListOfUnitsOfFiniteOrder; //Populate the list of cases bbb:=[]; ListOfCases:=[]; BuildListOfCases(1,~bbb, ~ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep,~ListOfCases); delete ModifiedListOfTuplesOfExponentsForPrimesDividingbbAbovep; ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// ////////////////////////////////////////////// /* Now we are ready to start the loop through the cases. We first declare the procedures that we will need in the loop. We also initialize some variables that we will use in the loop.  We  initialize them now to avoid having to add additional inputs for the procedures. */ ///////////////////////////////////////////// ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// 115  ////////////////////////////////////////////////////////////////// function MaxAbsLog(a) /* Input: a = number field element Output: The maximum of the numbers |Log(a^{(1)})|,..., =|Log(a^{(n)})|, where the a^{(i)} are the conjugates of a in \CC and Log denotes the principle branch of the complex logarithm */ minpoly:=MinimalPolynomial(a,IntegerRing()); ConjugatesOfa:=Roots(PolynomialRing(ComplexField()) ! minpoly); deg:=Degree(minpoly); max:=Modulus(Log(ConjugatesOfa[1][1])); for i:=2 to deg do temp:=Modulus(Log(ConjugatesOfa[i][1])); if temp gt max then max:=temp; end if; end for; return max; end function; ////////////////////////////////////////////////////////////////// function SmallestNonnegativeRemainderModpLToThem(x,l,m) /* Input: l = integer in {1,...,v}, m = positive integer, x = an element in the p_l-adic field Q_{p_l} that belongs to the subring Z_{p_l} (the ring of p_l-adic integers in Q_{p_l}). Output: The unique integer x^{m} in [0,p_l^m - 1] with ord_{p_l}(x - x^{m}) >= m */ y:=pAdicRing(p[l] : Precision:=padicprecision[l]) ! x; y:=pAdicQuotientRing(p[l], m) ! y; y:=IntegerRing() ! y; 116  if y lt 0 then y:=y+p[l]^m; end if; return y; end function; ////////////////////////////////////////////////////////////////// function LengthOfVector(v) /* Input: v = n by 1 column matrix Output: The length of v = the square root of the sum of the squares of the entries of v. */ size:=NumberOfRows(v); length:=0; for i:=1 to size do length +:= v[i][1]*v[i][1]; end for; length:=length^(1/2); return length; end function; ////////////////////////////////////////////////////////////////////// function pAdicLog(x,p) /* Input: p = rational prime, x = p-adic unit belonging to a finite extension of Q_p Output: the p-adic logarithm of x */ e:=AbsoluteRamificationIndex(Parent(x)); f:=AbsoluteInertiaDegree(Parent(x)); CandidateOrders:=Divisors(p^f - 1); o:=1; for oo in CandidateOrders do 117  if Valuation(x^oo - 1) gt 0 then o:=oo; break; end if; end for; j:=1; while p^j le e do j +:= 1; //j:=j+1; end while; return Log( x^(o*p^j) )/(o*p^j); end function; /////////////////////////////////////////////////////////////////////// function DistanceToNearestInteger(x) return Min( [x-Floor(x), Ceiling(x)-x] ); end function; /////////////////////////////////////////////////////////////////////// function RoundP(x) /* Input: x = a real number Ouput: The nearest positive integer to x.  If two postive integers are  the same distance to x, take the largest of the two. */ y:=Round(x); if y eq 0 then y:=1; end if; return y; end function; //////////////////////////////////////////////////////////////////////// procedure Choosettt(~yyy,~ttt,~potentialttt,~Floorsss,~min,~Bm,~mm,k) /* Assumption:  sss is a mm by 1 column vector with real entries  Input: Floorsss is a mm by 1 column vector with Floorsss[i][1]= 118  Floor(sss[i][1]) Input: yyy is a given mm by 1 vector with real entries Input: Bm is a given mm by mm matrix with real entries Input: potentialttt is a mm by 1 vector used as a placeholder by this procedure ttt is a mm by 1 column vector Input: min is a real number Assumption: This procedure calls itself.  When it is called by the user,  we assume min is equal to the length of the column vector Bm*Floorsss - yyy Input: k is a postive integer Assumption: This procedure calls itself.  When this procedure is called  by the user, we assume k=1. Result:  If the three assumptions above hold, then, after this procedure  is completed ttt, will be a mm by 1 column vector with integer entries such that |ttt[i][1] - sss[i][1]| <= 1 and such that the length of Bm*ttt - yyy is minimal (among all choices of ttt with integral and |ttt[i][1] - sss[i][1]| <= 1). Also, min will be the length of Bm*ttt - yyy. */ if k eq mm+1 then potentialmin:=LengthOfVector(Bm*potentialttt - yyy); if potentialmin lt min then ttt:=potentialttt; min:=potentialmin; end if; else for j:=0 to 1 do potentialttt[k][1]:=Floorsss[k][1]+j; Choosettt(~yyy,~ttt,~potentialttt,~Floorsss,~min,~Bm,~mm,k+1); end for; 119  end if; end procedure; //////////////////////////////////////////////////////////////////////// procedure CongruenceTest(~bbb,hhh,~passes,~Q,~J) /* Input: bbb is a sequence of #JJJ-1 integers. Input: hhh is a positive integer Assumption: Q[hhh] is a sequence of #JJJ+1 elements of the finite field Z/qZ, where q is a rational prime. Input: A boolean variable Assumption: bbb[i] = b_{JJJ[1+i]}, i=1 to #JJJ-1 Note: bbb[i] = b_{JJJ[1+i]} = b_{1+J[i]}=n_{J[i]} for i:=1 to #J Note: bbb[#J+i] = b_{JJJ[1+#J+i]} = b_{1+v+i}=a_i for i:=1 to r Assumption: q has at least three residue degree one prime ideals of OK above it. Assumption: For i=1,2,3, Qh[i]=[P_{i,JJJ[2]-1}, ..., P_{i,JJJ[1+#J]-1}, E_i1, ..., E_ir, A_i, m_i] =[P_{i,J[1]}, ..., P_{i,J[#J]}, E_i1, ..., E_ir, A_i, m_i] where m_i, A_i, P_ij, E_ij are the numbers from Section 22 corresponding to three residue degree one prime ideals of OK above q. Assumption: passes = true on entry to this procedure Result:  Provided the assumptions hold, passes will have the value true  if b_{JJJ[i+1]} satisfies the congruence (25) (with those Pij,n_j with j not in J removed) and will have the value false otherwise. */ prod1:=Q[hhh][1][#J+r+1]; for ii:=1 to #J+r do prod1 *:= Q[hhh][1][ii]^bbb[ii]; end for; prod2:=Q[hhh][2][#J+r+1]; for ii:=1 to #J+r do 120  prod2 *:= Q[hhh][2][ii]^bbb[ii]; end for; prod3:=Q[hhh][3][#J+r+1]; for ii:=1 to #J+r do prod3 *:= Q[hhh][3][ii]^bbb[ii]; end for; if not IsZero( (Q[hhh][2][#J+r+2]-Q[hhh][3][#J+r+2])*prod1 + (Q[hhh][3][#J+r+2]-Q[hhh][1][#J+r+2])*prod2 + (Q[hhh][1][#J+r+2]-Q[hhh][2][#J+r+2])*prod3 ) then passes:=false; end if; end procedure; ///////////////////////////////////////////////////////////////////////// procedure ThueMahlerEquationTest(~bbb,~Solutions,~ImageOfzetaC, ~ImageOfalphaC,~J,~ValueOfn,~kk,~hh,~ss,~tt); /* Use the tuple bbb (where bbb[i]=b_{JJJ[1+i]}, i=1 to #JJJ-1) and the sequence ValueOfn to get the tuple bb (where bb[i] = b_{1+i}=n_i, i=1 to v). Compute the corresponding X,Y.  We can actually compute X,Y before the  getting bb because \pi_{l}^{n_{l}} for l not in J is already part of \alpha.  We do this.  Test if (X,Y,b_{2},...,b_{1+v+r}) gives solution of the Thue-Mahler equation (1) and record it if so. Note: bbb[i]=b_{JJJ[1+i]} = b_{1+J[i]}=n_{J[i]}=bb[J[i]] for i:=1 to #J 121  Note: bbb[#J+i]=b_{JJJ[1+#J+i]} = b_{1+v+i}=a_i=bb[v+i] for i:=1 to r */ //Calculate X,Y if t gt 0 then BETA1:= ImageOfzetaC[s+1] * ImageOfalphaC[s+1]; for i:=1 to #J do BETA1 *:= ImageOfpiC[J[i]][kk[J[i]]][s+1]^bbb[i]; end for; for i:=1 to r do BETA1 *:= ImageOfepsC[i][s+1]^bbb[#J+i]; end for; THETA1:=thetaC[s+1]; Y:= -Imaginary(BETA1)/Imaginary(THETA1); X:=Round(  Real( BETA1 + THETA1*Y )  );  Y:=Round(Y); else //t=0 BETA1:= ImageOfzetaC[1] * ImageOfalphaC[1]; for i:=1 to #J do BETA1 *:= ImageOfpiC[J[i]][kk[J[i]]][1]^bbb[i]; end for; for i:=1 to r do BETA1 *:= ImageOfepsC[i][1]^bbb[#J+i]; end for; THETA1:=thetaC[1]; BETA2:= ImageOfzetaC[2] * ImageOfalphaC[2]; for i:=1 to #J do BETA2 *:= ImageOfpiC[J[i]][kk[J[i]]][2]^bbb[i]; end for; for i:=1 to r do 122  BETA2 *:= ImageOfepsC[i][2]^bbb[#J+i]; end for; THETA2:=thetaC[2]; Y:= Real(-(BETA1 - BETA2)/(THETA1 - THETA2)); X:=Round(Real(BETA1 + Y*THETA1)); Y:=Round(Y); end if; //Get the tuple bb from bbb and ValueOfn bb:=[]; for i:=1 to v do bb[i]:=ValueOfn[i]; //initialize end for; for i:=1 to #J do bb[J[i]]:=bbb[i]; end for; /*for i:=1 to r do bb[v+i]:=bbb[#J+i]; end for;*/  //Build RHS and LHS expressions RHSexpression:=a; for i:=1 to v do RHSexpression *:= p[i]^(bb[i]*hh[i] + ss[i] + tt[i]); end for; LHSexpression:= X^n + c[n]*Y^n; for i:=1 to n-1 do LHSexpression:=LHSexpression + c[i]*X^(n-i)*Y^i; end for; /*test if (X,Y,bb[1],...,bb[v])=(X,Y,b_{2},...,b_{1+v}) gives a solution of the sign-relaxed Thue-Mahler equation (in the form |LHS|-|RHS| = 0) */ 123  if IsZero(Abs(LHSexpression) - Abs(RHSexpression)) and Gcd(X,Y) eq 1 then temp:=[X,Y]; for i:=1 to v do Append( ~temp, bb[i]*hh[i] + ss[i] + tt[i] ); end for; Include(~Solutions,temp); end if; end procedure; ///////// procedure SieveBox(~bbb,~Solutions,~count,~Blower,~Bupper,~Q,~J, ~JJJ,~ValueOfn,~kk,~hh,~ss,~tt,~ImageOfzetaC,~ImageOfalphaC,k) /* This procedure calls itself. When this procedure is called by the user, we assume that k=1 and Solutions is a (possibly empty) list of solutions for the Thue-Mahler equation. After this procedure is finished executing its call by the user, Solutions will contain all the solutions (X,Y,n_1,...,n_v,a_1,...,a_r) of the sign-relaxed version of the Thue-Mahler equation that satisfy the currently known bounds on the n_i and the a_i and that satisfy the current case of (11).  Note that these bounds miss finitely many  explicitly known exceptional tuples. Recall:  Every solution of the Thue-Mahler equation satisfies some case  of (11). */ if k gt #J+r then //done k-1 loops and k-1 >= #J+r loops. So the tuple is //built //Test the tuple bbb for the congruences (25) 124  passes:=true; for hhh:=1 to #Q do //test the tuple for the q=q_hhh congruence (25) CongruenceTest(~bbb,hhh,~passes,~Q,~J); if passes eq false then break hhh; end if; end for; if passes eq true then /* Use the tuple bbb (where bbb[i]=b_{JJJ[1+i]}, i=1 to #JJJ-1) to get the tuplebb (where bb[i] = b_{1+i}, i=1 to v).  Compute the corresponding  X,Y. Test if (X,Y,b_{2},...,b_{1+v}) gives a solution of the sign-relaxed version of the Thue-Mahler equation (1) and record it if so. */ ThueMahlerEquationTest(~bbb,~Solutions,~ImageOfzetaC,~ImageOfalphaC,~J, ~ValueOfn,~kk,~hh,~ss,~tt); end if;  count +:= 1; if count eq 1000000 then print("done a millon tuples"); count:=0; end if;  else //k le #J+r. Done k-1 loops and k-1 < #J+r, so the tuple is not //built.  Only k-1 entries of the tuple have been picked.  for i:=Blower[k] to Bupper[k] do bbb[k]:=i; SieveBox(~bbb,~Solutions,~count,~Blower,~Bupper,~Q,~J,~JJJ,~ValueOfn, ~kk,~hh,~ss,~tt,~ImageOfzetaC,~ImageOfalphaC,k+1); end for; end if; end procedure;  125  //////////////////////////////////////////////////////////////// /* Start the loop over cases. The loop variable is iiii. */ //////////////////////////////////////////////////////////////// //Write("Cases.txt",#ListOfCases); //Write("Cases.txt",ListOfCases); print("Number of Cases:"); #ListOfCases; print("List of Cases:"); ListOfCases;  NumberOfCases:=#ListOfCases; time for iiii:=1 to NumberOfCases do //if iiii eq 3 then continue iiii; end if; //time for iiii:=3 to 3 do  /////////////////////////////////////////////////////////////////// /* Give easy-to-use names to the parameters determining the case of the factorized Thue-Mahler equation (11) that we are working with. same for some numbers derived from these parameters.  Do the  These names  essentially coincide with the names given to them in Section 6. */ /////////////////////////////////////////////////////////////// zeta:=ListOfCases[iiii][v+2];  126  kk:=[]; ppp:=[]; ppi:=[]; hh:=[]; ss:=[]; tt:=[]; for L:=1 to v do kk[L]:=ListOfCases[iiii][L][1][1]; //index of the unconstrained prime //above p[L] if kk[L] ne m[L] + 1 then ppp[L]:=pp[L][kk[L]]; //the unconstrained prime above p[L] hh[L]:=h[L][kk[L]]; //smallest positive integer such that ppp[L]^hh[L] is //principal ppi[L]:=pi[L][kk[L]]; //generator of ppp[L]^hh[L] else //kk[L] eq m[L] + 1 //there are no unramified degree one primes above p[L] ppp[L]:=ideal<OK | 1>; hh[L]:=1; ppi[L]:=OK ! 1; end if; ss[L]:=ListOfCases[iiii][L][3][1]; // the parameter s_L tt[L]:=0; for j:=1 to m[L] do tt[L]:=tt[L] + f[L][j]*ListOfCases[iiii][L][2][j]; //tt[L] = //ord_p[L](N(bb)) end for; end for; //end L loop /* The last thing to do is compute a generator alpha for the ideal \mathfrak{a} \mathfrak{b} \mathfrak{p}_{1}^{s_1} \ldots \mathfrak{p}_{v}^{s_v} from Section 6, provided it is principle. If the case of (11) we are considering has a solution, this ideal must be 127  principal.  So if it is not principle, we no there are no solutions to  case of (11) under consideration and skip directly to the next case (by using the continue command) */ aa:=PowerProduct(pI,ListOfCases[iiii][v+1]); aatimesbb:=aa; for L:=1 to v do aaa:=ListOfCases[iiii][L][2]; aatimesbb:=aatimesbb*PowerProduct(pp[L],aaa); end for; TheIdeal:=aatimesbb; for L:=1 to v do TheIdeal:=TheIdeal*(ppp[L]^ss[L]); end for; IsTheIdealPrinciple,alpha:=IsPrincipal(TheIdeal); //print("alpha"); //alpha; if IsTheIdealPrinciple eq false then continue iiii; end if; delete aa; delete aatimesbb; delete TheIdeal;  ///////////////////////////////////////////////////////////////////////// /* ImageOfzetap[l][i][j] := the image of zeta under the embedding of K into \overline{\QQ_{p_l}} defined by the map theta --> thetap[l][i][j]. ImageOfalphap[l][i][j] := the image of alpha under the embedding of K 128  into \overline{\QQ_{p_l}} defined by the map theta --> thetap[l][i][j]. */ //////////////////////////////////////////////////////////////////////// ImageOfzetap:=[]; for l:=1 to v do ImageOfzetap[l]:=[]; for i:=1 to m[l] do ImageOfzetap[l][i]:=[**]; for j:=1 to e[l][i]*f[l][i] do ImageOfzetap[l][i][j]:=0; for ii:= 1 to n do ImageOfzetap[l][i][j]:=ImageOfzetap[l][i][j] + zeta[ii]*ImageOfIntegralBasisElementp[l][i][j][ii]; end for; //ii end for; //j end for; //i end for; //l ImageOfalphap:=[]; for l:=1 to v do ImageOfalphap[l]:=[]; for i:=1 to m[l] do ImageOfalphap[l][i]:=[**]; for j:=1 to e[l][i]*f[l][i] do ImageOfalphap[l][i][j]:=0; for ii:= 1 to n do ImageOfalphap[l][i][j]:=ImageOfalphap[l][i][j] + alpha[ii]*ImageOfIntegralBasisElementp[l][i][j][ii]; end for; //ii end for; //j end for; //i end for; //l //////////////////////////////////////////////////////////////////////// 129  /* ImageOfzetaC[i] := the image of zeta under the embedding of K into \CC defined by the map theta --> thetaC[i]. ImageOfalphaC[i] := the image of alpha under the embedding of K into \CC defined by the map theta --> thetaC[i]. */ /////////////////////////////////////////////////////////////////////// ImageOfzetaC:=[ComplexField() | ]; for i:=1 to n do ImageOfzetaC[i]:=0; for ii:= 1 to n do ImageOfzetaC[i]:=ImageOfzetaC[i] + zeta[ii]*ImageOfIntegralBasisElementC[i][ii]; end for; //ii end for; //i ImageOfalphaC:=[ComplexField() | ]; for i:=1 to n do ImageOfalphaC[i]:=0; for ii:= 1 to n do ImageOfalphaC[i]:=ImageOfalphaC[i] + alpha[ii]*ImageOfIntegralBasisElementC[i][ii]; end for; //ii end for; //i ///////////////////////////////////////////////////////////////////////// /* For each p[l]: If we are NOT in the case where there are no unramified degree one primes above p[l], we fix the index i0 as in Section 7.  We will represent i0 by  the unique pair of integers (i,j) such that theta^{(i_0)} = theta_i^{(j)}. 130  i0[l] will be a sequence of two integers such that theta^{(i_0)} is represented by thetap[l][i0[l][1]][i0[l][2]] If there are no unramified degree one primes above p[l], i0[l] will still be a sequence of two integers, but it will have no real meaning. */ ///////////////////////////////////////////////////////////////////////// i0:=[]; for l:=1 to v do i0[l]:=[kk[l],1]; end for;  //////////////////////////////////////////////////////////////////////// /* For each p[l]: If we are NOT in the case where there are no unramified degree one primes above p[l], we choose the indices j,k according to the guidelines in Section 9.  As with i0 we represent j by a sequence of two integers  jjj[l] in such a way that theta^{(j)} is represented by thetap[l][jjj[l][1]][jjj[l][2]].  Similarly, for k.  Suppose we find a choice of j,k that lets us use Lemma 7.4 to compute n_l immediately.  If we compute a value for n_l that is not a nonnegative  integer, we move onto the next case using the continue command.  If we  compute a value for n_l that is nonnegative, then we absorb pi_l^n_l = ppi[l]^n_l into alpha and stop considering the index l in the rest of the algorithm, except in the last steps. If there are no unramified degree one primes above p[l], we know that the value of n_l is zero and we will stop considering the index l in the algorithm, except in the last steps. For l = 1,...,v: 131  If we know the value of n_l, then ValueOfn[l]:= that value If we don’t know the value of n_l, then ValueOfn[l]:=-1 JJ = set of those indices l in {1,...,v} for which there is at least one unramified degree one prime above p[l]. By the end of this block of code, J = the set of all indices in {1,...,v} that we need to consider in the rest of the algorithm, except the last steps.  These are the indices l  for which there is at least one unramified degree one prime above p[l] and there is no choice of j,k that lets us use Lemma 7.4 to compute n_l. It will be convenient to have defined the following set of indices JJJ := {1} union { 1+l : l in J} union { 1+v+i : i in {1,...,r}} I = set of those l in J for which there is no choice of j,k that lets us use Lemma 8.3 to bound n_l. I2 = J - I. For each l in I, jl[l] is the unique index such that JJJ[jl[l]]=l+1. We will compute delta_1 and delta_2 for each l in J We will compute the numbers alpha_i from Section 8 for each l in J: alpha_i = LogarithmicAlphap[l][i] We could compute the alpha_i and delta1, delta2 from Section 8 for each l in {1,...,v} for which there is at least one unramified degree one prime above p[l] or even for each l in {1,...,v}, but we don’t For l in I: SpecialCase[l] = true if the choice of j,k puts us in the special case of Section 17. SpecialCase[l] = false otherwise (general case) 132  Nstar[l] = N_{l}^{*} from Section 11. Initialize ihat[l] from Section 17.  Note ihat[l] in JJJ, ihat[l] neq 2.  Intizalize istar[l]. Eventually, istar[l] will be the index in {2,...,1+v+r} such that ihat[l] = JJJ[istar[l]]. Possibly define ihat[l] and istar[l] for some l. */ //////////////////////////////////////////////////////////////////////// ValueOfn:=[]; for l:=1 to v do ValueOfn[l]:=-1; //initialize end for; Nstar:=[]; for l:=1 to v do Nstar[l]:=padicprecision[l]+1; //initialize /*the largest possible value of Valuation(x) for x an element of FFFppF[l] is padicprecision[l]*/ end for; u:=[]; for l:=1 to v do u[l]:=-1; //initialize end for; SpecialCase:=[]; for l:=1 to v do SpecialCase[l]:=false; //initialize end for;  133  ihat:=[]; for l:=1 to v do ihat[l]:=0; //initialize to a value that ihat[l] can never assume end for; istar:=[]; for l:=1 to v do istar[l]:=0; //initialize to a value that ihat[l] can never assume end for;  //start with J={1,...,v} J:=[]; for l:=1 to v do J[l]:=l; end for; /* Remove from J all the indices l such that p[l] has no unramified degree one primes above it.  After they are removed, we know that, for every l  in J, g has at least one linear factor in Q_{p_l}.  Also set the value of  n_l for these indices l. */ for l:=1 to v do if kk[l] eq m[l]+1 then /*no degree one unramified primes above p_l*/ ValueOfn[l]:=0; /* now absorb pi_l^n_l = ppi[l]^n_l into alpha and remove the index l from J */ alpha:=alpha*ppi[l]^ValueOfn[l]; Exclude(~J,l); end if; end for; /*JJ = set of those indices l in {1,...,v} for which there is at least one unramified degree one prime above p[l].*/ 134  JJ:=J; I:=J;  //initialize delta1,delta2 delta1:=[**]; delta2:=[**]; for l:=1 to v do delta1[l]:=FFFppF[l] ! 1; delta2[l]:=FFFppF[l] ! 1; end for;  //Now select j,k.  We will remove indices from J and I (if possible) as  //we go. jjj:=[]; kkk:=[]; LogarithmicAlphap:=[]; CoefficientsLogarithmicAlphap:=[]; for l:=1 to v do LogarithmicAlphap[l]:=[**]; CoefficientsLogarithmicAlphap[l]:=[**]; for i:=1 to 1+v+r do LogarithmicAlphap[l][i]:=0; CoefficientsLogarithmicAlphap[l][i]:=0; end for; end for;  for l in JJ do /*try to find a choice of j,k that gives ord_{p_l}(delta_1) \neq 0*/ for i:=1 to m[l] do if i eq i0[l][1] then continue i; end if; 135  for j:=1 to e[l][i]*f[l][i] do jjj[l]:=[i,j]; for ii:=i to m[l] do if ii eq i0[l][1] then continue ii; end if; for jj:=1 to e[l][ii]*f[l][ii] do if ii eq i and jj le j then continue jj; end if; kkk[l]:=[ii,jj]; /*the last if statement ensures that we never try both j=a,k=b and j=b,k=a*/ delta1[l]:= ((thetap[l][i0[l][1]][i0[l][2]] thetap[l][jjj[l][1]][jjj[l][2]]) / (thetap[l][i0[l][1]][i0[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]])) *(ImageOfzetap[l][kkk[l][1]][kkk[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) *(ImageOfalphap[l][kkk[l][1]][kkk[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); if Valuation(delta1[l]) ne 0 then /* print("Valuation(delta1[l]):"); Valuation(delta1[l]); print("iiii"); iiii; print("l:"); l; print("jjj[l] and kkk[l]:"); jjj[l]; kkk[l]; */ delta2[l]:= ((thetap[l][jjj[l][1]][jjj[l][2]] 136  thetap[l][kkk[l][1]][kkk[l][2]]) / (thetap[l][kkk[l][1]][kkk[l][2]] - thetap[l][i0[l][1]][i0[l][2]])) *(ImageOfzetap[l][i0[l][1]][i0[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) *(ImageOfalphap[l][i0[l][1]][i0[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); //print("Valuation(delta2[l])"); //Valuation(delta2[l]); ValueOfn[l]:= (Min([Valuation(delta1[l]),0]) - Valuation(delta2[l]))/hh[l]; //print("ValueOfn[l]"); //ValueOfn[l]; if not IsIntegral(ValueOfn[l]) or ValueOfn[l] lt 0 then continue iiii; end if; // b/c no solutions /* now absorb pi_l^n_l = ppi[l]^n_l into alpha and remove the index l from J */ //print("alpha"); //alpha; //print("ppi[l]"); //ppi[l]; alpha:=alpha*ppi[l]^ValueOfn[l]; Exclude(~J,l); //print("alpha"); //alpha;  //Recompute ImageOfalphap[l] ImageOfalphap[l]:=[]; 137  for i1:=1 to m[l] do ImageOfalphap[l][i1]:=[**]; for j1:=1 to e[l][i1]*f[l][i1] do ImageOfalphap[l][i1][j1]:=0; for ii1:= 1 to n do ImageOfalphap[l][i1][j1]:=ImageOfalphap[l][i1][j1] + alpha[ii1]*ImageOfIntegralBasisElementp[l][i1][j1][ii1]; end for; //ii1 end for; //j1 end for; //i1 //Recompute ImageOfalphaC ImageOfalphaC:=[ComplexField()|]; for i1:=1 to n do ImageOfalphaC[i1]:=0; for ii1:= 1 to n do ImageOfalphaC[i1]:=ImageOfalphaC[i1] + alpha[ii1]*ImageOfIntegralBasisElementC[i1][ii1]; end for; //ii1 end for; //i1  //done choosing j,k for the current l, move onto the next l continue l; end if; end for; //end jj loop end for; //end ii loop end for; //end j loop end for; //end i loop end for; //end l loop //We are now finished defining J /*J = the set of all indices in {1,...,v} that we need to consider in the rest of the algorithm, except the last steps.  These are the indices l 138  for which there is at least one unramified degree one prime above p[l] and there is no choice of j,k that lets us use Lemma 7.4 to compute n_l.*/  //////////// /* It will be convenient to have defined the following set of indices JJJ := {1} union { 1+l : l in J} union { 1+v+i : i in {1,...,r}} */ ////////// JJJ:=[1]; for l in J do Append(~JJJ,1+l); end for; for i:=1 to r do Append(~JJJ,1+v+i); end for; /*we start with I = J and remove indices from I as we go. Want to make I = set of those l in J for which there is no choice of j,k that lets us use Lemma 8.3 to bound n_l.*/ I:=J; for l in J do /* if the program makes it this far, we know that there is no choice of j,k such that ord_{p_l}(delta_1) \neq 0. Now we try to find a choice of j,k such that Lemma 8.3 can be used to find an upper bound on n_l */ for i:=1 to m[l] do if i eq i0[l][1] then continue i; end if; for j:=1 to e[l][i]*f[l][i] do jjj[l]:=[i,j]; for ii:=i to m[l] do 139  if ii eq i0[l][1] then continue ii; end if; for jj:=1 to e[l][ii]*f[l][ii] do if ii eq i and jj le j then continue jj; end if; kkk[l]:=[ii,jj]; /*the last if statement ensures that we never try both j=a,k=b and j=b,k=a*/ //define delta1[l] and delta2[l] delta1[l]:= ((thetap[l][i0[l][1]][i0[l][2]] thetap[l][jjj[l][1]][jjj[l][2]]) / (thetap[l][i0[l][1]][i0[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]])) *(ImageOfzetap[l][kkk[l][1]][kkk[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]])* (ImageOfalphap[l][kkk[l][1]][kkk[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); delta2[l]:= ((thetap[l][jjj[l][1]][jjj[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]]) / (thetap[l][kkk[l][1]][kkk[l][2]] - thetap[l][i0[l][1]][i0[l][2]])) *(ImageOfzetap[l][i0[l][1]][i0[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) *(ImageOfalphap[l][i0[l][1]][i0[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); //define alpha_i’s for i in JJJ LogarithmicAlphap[l][1]:=pAdicLog(delta1[l],p[l]); for iii in J do LogarithmicAlphap[l][1+iii]:= pAdicLog(ImageOfpip[iii][kk[iii]][l][kkk[l][1]][kkk[l][2]]/ 140  ImageOfpip[iii][kk[iii]][l][jjj[l][1]][jjj[l][2]],p[l]); end for; for iii:=1 to r do LogarithmicAlphap[l][1+v+iii]:= pAdicLog(ImageOfepsp[iii][l][kkk[l][1]][kkk[l][2]]/ ImageOfepsp[iii][l][jjj[l][1]][jjj[l][2]],p[l]); end for; //get the coefficients of the alpha_i’s: the alpha_{ih}’s for iii in JJJ do CoefficientsLogarithmicAlphap[l][iii]:= GetCoefficients(LogarithmicAlphap[l][iii],l); end for; /*Check if Lemma 8.3 can be applied and, if so, compute Nstar[l] = N_{l}^{*}.*/ min:=Valuation(LogarithmicAlphap[l][JJJ[2]]); for iii:=2 to #JJJ do if Valuation(LogarithmicAlphap[l][JJJ[iii]]) lt min then min:=Valuation(LogarithmicAlphap[l][JJJ[iii]]); end if; end for; if Valuation(LogarithmicAlphap[l][1]) lt min then temp:=Max([  Floor((1/hh[l])*(1/(p[l]-1) - Valuation(delta2[l]))),  Ceiling((1/hh[l])*(min - Valuation(delta2[l])))-1  ]);  if temp lt 0 then continue iiii; end if; //no solutions in the current //case if temp lt Nstar[l] then Nstar[l]:=temp; end if; end if; for hhh:=1 to SS[l] do min:=Valuation(CoefficientsLogarithmicAlphap[l][JJJ[2]][hhh]); for iii:=2 to #JJJ do 141  if Valuation(CoefficientsLogarithmicAlphap[l][JJJ[iii]][hhh]) lt min then min:=Valuation(CoefficientsLogarithmicAlphap[l][JJJ[iii]][hhh]); end if; end for; //end iii loop if Valuation(CoefficientsLogarithmicAlphap[l][1][hhh]) lt min then temp:=Max([  Floor((1/hh[l])*(1/(p[l]-1) - Valuation(delta2[l]))),  Ceiling((1/hh[l])*(u[l] + min - Valuation(delta2[l])))-1  ]);  if temp lt 0 then continue iiii; end if; //no solutions in the current //case if temp lt Nstar[l] then Nstar[l]:=temp; end if; end if; end for; //end hhh loop if Nstar[l] lt padicprecision[l]+1 then //we’ve found a choice of j,k that lets us use Lemma 8.3 to bound n_l Exclude(~I,l); continue l; end if; end for; end for; end for; end for;  /* If the program makes it this far, we know that there is no choice of j,k such that ord_{p_l}(delta_1) \neq 0 and also there is no choice of j,k that lets us use Lemma 8.3 to get an upper bound on n_l.  So we will  eventually need to use linear forms in logs + lattice reduction to get a small upper bound on n_l Now we try to find a choice of j,k according to the remaining guidlines 142  in Section 9. alpha_i /  The whole point is to try to choose j,k so that  alpha_{ihat} is in Q_{p_l} for all i in J.  For each candidate j,k, we first do some simple checks for conditions that imply alpha_i /  alpha_{ihat} is in Q_{p_l} for all i in J.  we are forced to check directly whether alpha_i /  If  alpha_{ihat} is in  Q_{p_l} for all i, we do this for all candidates for ihat.  If we find a  candidate for ihat that works, we remember it. */  /* check if we can take j,k so that theta^{(j)},theta^{(k)} are roots of linear factors of g(t) in Q_{p_l}[t] */ jfound:=false; for i:=1 to m[l] do if i eq i0[l][1] then continue i; end if; if Degree(gp[l][i]) eq 1 then if jfound eq false then jjj[l]:=[i,1]; jfound:=true; continue i; end if; if jfound eq true then kkk[l]:=[i,1]; /* we’ve found a choice for j,k so that theta^{(j)},theta^{(k)} are roots of linear factors of g(t) in Q_{p_l}[t] Section 17 */ SpecialCase[l]:=true; continue l; end if; end if; end for; //end i loop  143  /* check if we can take j,k so that theta^{(j)}, theta^{(k)} are the roots of a degree 2 factor of g(t) Q_{p_l}[t] */ for i:=1 to m[l] do if Degree(gp[l][i]) eq 2 then jjj[l]:=[i,1]; kkk[l]:=[i,2]; /* we’ve found a j,k so that theta^{(j)}, theta^{(k)} are the roots of a degree 2 factor of g(t) Q_{p_l}[t] */ SpecialCase[l]:=true; continue l; end if; end for;  /* If there is a nonlinear factor g^{\prime}(t) of g(t) in Q_{p_l}[t] such that the extension of Q_{p_l} that g^{\prime}(t) generates contains all the roots of g^{\prime}(t) (equivalently, the extension is Galois), then taking j,k so that \theta^{(j)},\theta^{(k)} are two roots of g^{\prime}(t) will ensure that alpha_i /  alpha_{ihat} is in Q_{p_l}  for all i. If an irreducible polynomial over Q_{p_l}[t] is neither inertial nor eisenstein, MAGMA does not support directly constructing the extension of Q_{p_l} generated by the polynomial.  However, we know that the  extension of Q_{p_l} generated by g^{\prime}(t) is isomorphic to the completion of K at the prime ideal above p_l which corresponds to g^{\prime}(t). Note also that irreducible polynomials over p-adic fields have no 144  repeated roots (since p-adic fields have characteristic zero). */ for i:=1 to m[l] do if Degree(gp[l][i]) gt 1 and #Roots(gp[l][i],Kpp[l][i]) eq Degree(gp[l][i]) then jjj[l]:=[i,1]; kkk[l]:=[i,2]; /* we’ve found j,k that ensure alpha_i / alpha_{ihat} is in Z_{p_l} for all i and all candidates for ihat. */ SpecialCase[l]:=true; continue l; end if; end for;  /* Now we do the more difficult checks to see if we can choose j,k such that alpha_i /  alpha_{ihat} is in Z_{p_l} for all i,j  */  for i:=1 to m[l] do if i eq i0[l][1] then continue i; end if; for j:=1 to e[l][i]*f[l][i] do jjj[l]:=[i,j]; for ii:=i to m[l] do if ii eq i0[l][1] then continue ii; end if; for jj:=1 to e[l][ii]*f[l][ii] do if ii eq i and jj le j then continue jj; end if; kkk[l]:=[ii,jj]; 145  //define delta1[l] and delta2[l] delta1[l]:= ((thetap[l][i0[l][1]][i0[l][2]] - thetap[l][jjj[l][1]][jjj[l][2]]) / (thetap[l][i0[l][1]][i0[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]])) *(ImageOfzetap[l][kkk[l][1]][kkk[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) *(ImageOfalphap[l][kkk[l][1]][kkk[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); delta2[l]:= ((thetap[l][jjj[l][1]][jjj[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]]) / (thetap[l][kkk[l][1]][kkk[l][2]] - thetap[l][i0[l][1]][i0[l][2]])) *(ImageOfzetap[l][i0[l][1]][i0[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) *(ImageOfalphap[l][i0[l][1]][i0[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); //define alpha_i’s for i in JJJ LogarithmicAlphap[l][1]:=pAdicLog(delta1[l],p[l]); for iii in J do LogarithmicAlphap[l][1+i]:= pAdicLog(ImageOfpip[iii][kk[iii]][l][kkk[l][1]][kkk[l][2]] /ImageOfpip[iii][kk[iii]][l][jjj[l][1]][jjj[l][2]],p[l]); end for; for iii:=1 to r do LogarithmicAlphap[l][1+v+i]:= pAdicLog(ImageOfepsp[iii][l][kkk[l][1]][kkk[l][2]] 146  /ImageOfepsp[iii][l][jjj[l][1]][jjj[l][2]],p[l]); end for; //get the coefficients of the alpha_i’s: the alpha_{ih}’s for iii in JJJ do CoefficientsLogarithmicAlphap[l][iii]:= GetCoefficients(LogarithmicAlphap[l][iii],l); end for; /* Check if there is a choice of j,k such that the alpha_i (i in JJJ) all belong to $\QQ_{p_l}$. */ flag:=true; for iii in JJJ do for hhh:=2 to SS[l] do if not IsZero(CoefficientsLogarithmicAlphap[l][iii][hhh]) then flag:=false; break iii; end if; end for; end for; if flag eq true then //we’ve found a choice of j,k with desired properties SpecialCase[l]:=true; continue l; end if;  /* Now we check directly whether we have alpha_i / for all i.  alpha_{ihat} in Q_{p_l}  We do this for all candidates for ihat.  */ //find all candidates for istar (hence for ihat) candidatesforistar:=[]; min:=Valuation(LogarithmicAlphap[l][JJJ[2]]); 147  for iii:=JJJ[2] to JJJ[#JJJ] do if Valuation(LogarithmicAlphap[l][iii]) lt min then min:=Valuation(LogarithmicAlphap[l][iii]); end if; end for; for iiiiii:=2 to #JJJ do iii:=JJJ[iiiiii]; if min eq Valuation(LogarithmicAlphap[l][iii]) then Append(~candidatesforistar,iiiiii); end if; end for; /* For all candidates for ihat, check whether alpha_i /  alpha_{ihat} in  Q_{p_l} for all i in JJJ */ temp:=[]; for istarstar in candidatesforistar do ihathat:=JJJ[istarstar]; for iii in JJJ do temp[iii]:=GetCoefficients(LogarithmicAlphap[l][iii] /LogarithmicAlphap[l][ihathat],l); end for; flag:=true; for iii in JJJ do for hhh:=2 to SS[l] do if not IsZero(temp[iii][hhh]) then flag:=false; break iii; end if; end for; end for; if flag eq true then /* we’ve found a choice of j,k with the desired properties */ SpecialCase[l]:=true; ihat[l]:=ihathat; istar[l]:=istarstar; continue l; end if; end for;  148  end for; //jj end for; //ii end for; //j end for; //i  /* If the program makes it this far, it means there is no choice of j,k for which ord_{p_l}(delta_1) = 0, no choice for which Lemma 8.3 gives an upper bound for n_l, and no choice which puts us in the special case of Section 17 (alpha_i /  alpha_{ihat} in Z_{p_l} for all i).  We know that there are at most two degree one factors of g(t) in Q_{p_l}[t] and there are no degree two factors. factor of degree >= 3.  So there is at least one  We choose a nonlinear factor of g(t) in  Q_{p_l}[t] of minimal degree and choose j,k so that \theta^{(j)}, \theta^{(k)} are roots of that factor. */ minimaldegreegreaterthan1:=Degree(FFFppF[l],PrimeField(FFFppF[l])); //initialize, no gp[l][i] can have degree strictly larger than this for i:=1 to m[l] do if Degree(gp[l][i]) gt 1 and Degree(gp[l][i]) lt minimaldegreegreaterthan1 then minimaldegreegreaterthan1:=Degree(gp[l][i]); jjj:=[i,1]; kkk:=[i,2]; end if; end for; end for; //end l loop I2:=J; //J = I union I2, I intersect I2 = empty 149  for l in I do Exclude(~I2,l); end for; //For each l in I, jl[l] is the unique index such that JJJ[jl[l]]=l+1. jl:=[]; for i:=1 to v do jl[i]:=0; end for; for l in I do for i:=2 to 1+#J do if JJJ[i] eq l+1 then jl[l]:=i; break i; end if; end for; end for;  //////////////////////////////////////////////////////////////////////// /* For each l in I, we will find a value for the index ihat and compute the beta_i’s from Section 17: ihat[l], beta[l][i] We also define d_l from Section 17: dd[l] It can be that a choice of ihat[l] was already made in the last step. If ihat[l] >0, we know this choice has been made.  Otherwise, ihat[l] = 0  and we know a choice hasn’t been made yet. */ //////////////////////////////////////////////////////////////////////// beta:=[]; dd:=[]; for l:=1 to v do beta[l]:=[**]; end for;  150  for l in I do //define delta1[l] and delta2[l] delta1[l]:= ((thetap[l][i0[l][1]][i0[l][2]] - thetap[l][jjj[l][1]][jjj[l][2]]) / (thetap[l][i0[l][1]][i0[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]])) *(ImageOfzetap[l][kkk[l][1]][kkk[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) * (ImageOfalphap[l][kkk[l][1]][kkk[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); delta2[l]:= ((thetap[l][jjj[l][1]][jjj[l][2]] - thetap[l][kkk[l][1]][kkk[l][2]]) / (thetap[l][kkk[l][1]][kkk[l][2]] - thetap[l][i0[l][1]][i0[l][2]])) *(ImageOfzetap[l][i0[l][1]][i0[l][2]] / ImageOfzetap[l][jjj[l][1]][jjj[l][2]]) *(ImageOfalphap[l][i0[l][1]][i0[l][2]] / ImageOfalphap[l][jjj[l][1]][jjj[l][2]]); //define alpha_i’s LogarithmicAlphap[l][1]:=pAdicLog(delta1[l],p[l]); for iii in J do LogarithmicAlphap[l][1+iii]:= pAdicLog(ImageOfpip[iii][kk[iii]][l][kkk[l][1]][kkk[l][2]] /ImageOfpip[iii][kk[iii]][l][jjj[l][1]][jjj[l][2]],p[l]); end for; for iii:=1 to r do 151  LogarithmicAlphap[l][1+v+iii]:= pAdicLog(ImageOfepsp[iii][l][kkk[l][1]][kkk[l][2]] /ImageOfepsp[iii][l][jjj[l][1]][jjj[l][2]],p[l]); end for;  if SpecialCase[l] eq true then if ihat[l] eq 0 then min:=Valuation(LogarithmicAlphap[l][JJJ[2]]); ihat[l]:=JJJ[2]; istar[l]:=2; for i:=3 to #JJJ do iii:=JJJ[i]; if Valuation(LogarithmicAlphap[l][iii]) lt min then min:=Valuation(LogarithmicAlphap[l][iii]); ihat[l]:=iii; istar[l]:=i; end if; end for; end if; for iii:=1 to 1+v+r do beta[l][iii] := -LogarithmicAlphap[l][iii]/LogarithmicAlphap[l][ihat[l]]; /* For l in I, we know that the beat_i’s live in Z_{p_l}.  So their  coefficients on the power basis for FFFppF[l] are all zero, except for the first.  We can use this to save on computations with the beta_i’s:  */ beta[l][iii] := GetCoefficients(beta[l][iii],l)[1]; end for; dd[l]:=Valuation(delta2[l]) - Valuation(LogarithmicAlphap[l][ihat[l]]); else //SpecialCase[l] eq false //general case 152  //get the coefficients of the alpha_i’s: the alpha_{ih}’s for iii:=1 to 1+v+r do CoefficientsLogarithmicAlphap[l][iii]:= GetCoefficients(LogarithmicAlphap[l][iii],l); end for; // Choose an index hhh in {1,...,S[l]} arbitrarily hhh:=1; if ihat[l] eq 0 then min:=Valuation(CoefficientsLogarithmicAlphap[l][JJJ[2]][hhh]); ihat[l]:=JJJ[2]; istar[l]:=2; for i:=3 to #JJJ do iii:=JJJ[i]; if Valuation(CoefficientsLogarithmicAlphap[l][iii][hhh]) lt min then min:=Valuation(CoefficientsLogarithmicAlphap[l][iii][hhh]); ihat[l]:=iii; istar[l]:=i; end if; end for; end if; for iii:=1 to 1+v+r do beta[l][iii] := -CoefficientsLogarithmicAlphap[l][iii][hhh] / CoefficientsLogarithmicAlphap[l][ihat[l]][hhh]; end for; dd[l]:=Valuation(delta2[l]) - Valuation(LogarithmicAlphap[l][ihat[l]]) - u[l]; end if; end for; //end l 153  //////////////////////////////////////////////////////////////////////// //////////////////////////////////// ///////////////// /* Compute c_1(l) = c1[l] for each l in I */ //////////////// /////////////////////////////////// //////////////////////////////////////////////////////////////////////// ////////////////////// /* For each l in I: Find preimages in FFF of theta^{(i_0)}, theta^{(j)}, theta^{(k)} under the embedding sigma = mFFFppF[L] of FFF into FFFppF[l].  We choose not to  use MAGMA’s bulit in preimage-finder to avoid round-off errors. To find the preimage of theta^{(i_0)}, we actually find the index ii0 in {1,...,n} such that mFFFppF[L](thetaF[ii0]) = thetap[l][i0[1]][i0[2]]. Similarly for theta^{(j)}, theta^{(k)}. PreimageOfalphaj = preimage in FFF of \alpha^{(j)} under the embedding sigma = mFFFppF[L] of FFF into FFFppF[l] PreimageOfzetaj = preimage in FFF of \zeta^{(j)} under the embedding sigma = mFFFppF[L] of FFF into FFFppF[l] PreimageOfalphak = preimage in FFF of \alpha^{(k)} under the embedding sigma = mFFFppF[L] of FFF into FFFppF[l] 154  PreimageOfzetak = preimage in FFF of \zeta^{(k)} under the embedding sigma = mFFFppF[L] of FFF into FFFppF[l] We also find the preimages of pi_{i}^{(j)}, pi_{i}^{(k)}, eps_{i}^{(j)}, eps_{i}^{(k)} */ ///////////////////// //intialization c1:=[**]; rootsofginFFFppF:=[**]; PreimageOfalphaj:=[]; PreimageOfzetaj:=[]; PreimageOfalphak:=[]; PreimageOfzetak:=[]; for l:=1 to v do c1[l]:=0; rootsofginFFFppF[l]:=mFFFppF[l](rootsofginFFF); end for; for l in I do //find preimage of \theta^{(i_0)} max:=Valuation(thetap[l][i0[l][1]][i0[l][2]] - rootsofginFFFppF[l][1]); ii0:=1; for i:=2 to n do if Valuation(thetap[l][i0[l][1]][i0[l][2]] - rootsofginFFFppF[l][i]) gt max then max:=Valuation(thetap[l][i0[l][1]][i0[l][2]] - rootsofginFFFppF[l][i]); ii0:=i; end if; end for; //find preimage of \theta^{(j)} 155  max:=Valuation(thetap[l][jjj[l][1]][jjj[l][2]] - rootsofginFFFppF[l][1]); ijjj:=1; for i:=2 to n do if Valuation(thetap[l][jjj[l][1]][jjj[l][2]] - rootsofginFFFppF[l][i]) gt max then max:=Valuation(thetap[l][jjj[l][1]][jjj[l][2]] - rootsofginFFFppF[l][i]); ijjj:=i; end if; end for; //find preimage of \theta^{(k)} max:=Valuation(thetap[l][kkk[l][1]][kkk[l][2]] - rootsofginFFFppF[l][1]); ikkk:=1; for i:=2 to n do if Valuation(thetap[l][kkk[l][1]][kkk[l][2]] - rootsofginFFFppF[l][i]) gt max then max:=Valuation(thetap[l][kkk[l][1]][kkk[l][2]] - rootsofginFFFppF[l][i]); ikkk:=i; end if; end for; PreimageOfzetaj:=0; for i:= 1 to n do PreimageOfzetaj:=PreimageOfzetaj + zeta[i]*ImageOfIntegralBasisElementF[ijjj][i]; end for; //i PreimageOfalphaj:=0; for i:= 1 to n do PreimageOfalphaj:=PreimageOfalphaj + alpha[i]*ImageOfIntegralBasisElementF[ijjj][i]; end for; //i PreimageOfzetak:=0; for i:= 1 to n do PreimageOfzetak:=PreimageOfzetak + zeta[i]*ImageOfIntegralBasisElementF[ikkk][i]; 156  end for; //i PreimageOfalphak:=0; for i:= 1 to n do PreimageOfalphak:=PreimageOfalphak + alpha[i]*ImageOfIntegralBasisElementF[ikkk][i]; end for; //i /* Note that: preimage of pi_{i}^{(j)} = ImageOfpiF[i][kk[i]][ijjj] preimage of pi_{i}^{(k)} = ImageOfpiF[i][kk[i]][ikkk] preimage of eps_{i}^{(j)} = ImageOfepsF[i][ijjj] preimage of eps_{i}^{(k)} = ImageOfepsF[i][ikkk] */ /////////////////////////////////////// /* Define the alpha_i for i in J, construct L, and find the prime ideal of L corresponding to sigma (see Section 11). */ ////////////////////////////////////// alphaALGEBRAIC:=[FFF|]; for i:=1 to 1 + v + r do alphaALGEBRAIC[i]:=1; //initialize end for; alphaALGEBRAIC[1]:= (thetaF[ii0] - thetaF[ijjj] / thetaF[ii0] - thetaF[ikkk]) *(PreimageOfalphak/PreimageOfalphaj)*(PreimageOfzetak/PreimageOfzetaj); for i in J do alphaALGEBRAIC[1+i]:= ImageOfpiF[i][kk[i]][ikkk]/ImageOfpiF[i][kk[i]][ijjj]; end for; for i:=1 to r do alphaALGEBRAIC[1+v+i]:= ImageOfepsF[i][ikkk]/ImageOfepsF[i][ijjj]; 157  end for; LL:=sub<FFF | alphaALGEBRAIC>; LLx<x>:=PolynomialRing(LL); D:=Degree(LL); mm:=1+#J+r; ppL:=ppF[l] meet MaximalOrder(LL); eppL:=RamificationIndex(ppL); fppL:=InertiaDegree(ppL); //////////////////////////////////////////////////////////////////////// /* Compute all the constants that go into Yu’s Theorem */ /// //////////////////////////////////////////////////////////////////////// d:=D; ff:=fppL; if p[l] eq 2 and IsIrreducible(x^2 + x + 1) then d:=2*D; ff:=Max([2,fppL]); end if; if p[l] ge 3 and ((p[l]^fppL mod 4) eq 1) and IsIrreducible(x^3 + x^2 + x + 1) then d:=2*D; ff:=Max([2,fppL]); end if; delete x; delete LLx; kappa:=Floor(2*eppL*Log(p[l])/(p[l]-1)); 158  //note d \geq 2 for us // default case: p=2 kappa1:=160; kappa2:=32; kappa3:=40; kappa4:=276; kappa5:=16; kappa6:=8; if p[l] eq 3 then kappa1:=759; kappa2:=16; kappa3:=20; kappa4:=1074; kappa5:=8; kappa6:=4; end if; if p[l] ge 5 then kappa5:=8; kappa6:=4; if eppL eq 1 then kappa2:=8*(p[l]-1)/(p[l]-2); kappa3:=10; if p[l] mod 4 eq 1 then kappa1:=1473; kappa4:=394*(p[l]-1)/(p[l]-2); end if; if p[l] mod 4 eq 3 then kappa1:=1282; kappa4:=366*(p[l]-1)/(p[l]-2); end if; 159  end if; if eppL ge 2 then kappa2:=16; kappa3:=20; if p[l] eq 5 then kappa1:=319; kappa4:=402; end if; if p[l] ge 7 and p[l] mod 4 eq 1 then kappa1:=1502; kappa4:=1372; end if; if p[l] ge 7 and p[l] mod 4 eq 3 then kappa1:=2190; kappa4:=1890; end if; end if; end if; c2:=((((mm+1)^(mm+2)) * d^(mm+2))/(Factorial(mm-1))) * ( p[l]^ff / (ff*Log(p[l]))^3 ) * Max([1,Log(d)]) * Max( [4+Log(mm+1)+Log(d),eppL,ff*Log(p[l])] );  halphaALGEBRAIC:=[]; for i:=1 to 1+v+r do halphaALGEBRAIC[i]:=AbsoluteLogarithmicHeight(alphaALGEBRAIC[i]); end for; c3prime:=kappa1 * kappa2^mm * (mm / ff*Log(p[l]) )^(mm-1); for i in JJJ do c3prime:=c3prime*Max([ halphaALGEBRAIC[i], ff*Log(p[l])/(kappa3*(mm+4)*d) ]); end for; 160  c3primeprime:= kappa4 * kappa5^mm * Exp(mm) * p[l]^(kappa*(mm-1)); for i in JJJ do c3primeprime:=c3primeprime*Max([ halphaALGEBRAIC[i], ff*Log(p[l])/(Exp(2)*kappa6*(p[l]^kappa)*d)  ]);  end for; qu:=4; //default case: p \geq 3, p^f_pp \equiv 1 mod 4 if p[l] eq 2 then qu:=3; end if; if p[l] ge 3 and p[l]^fppL mod 4 eq 3 then qu:=1; end if; c1[l]:=(1/eppL)*(c2/qu)*Max([c3prime,c3primeprime]); end for; //end l loop //////////////////////////////////////////////////////////////////////// /* Done computing c1[l] for all l in I */ //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /* Compute c4, c5 (with primed versions), c7 */ ////////////////////////////////////////////////////////////////////////  c4prime:=0; for l in I do if c4prime lt c1[l]/hh[l] then c4prime:=c1[l]/hh[l]; end if; end for; c4primeprime:=0; c5primeprime:=0; 161  for l in I2 do if c4primeprime lt Nstar[l] then c4primeprime:=Nstar[l]; end if; end for; c4:=c4prime; if c4prime lt c4primeprime then c4:=c4primeprime; end if; c5:=0; for l in I do if c5 lt -Valuation(delta2[l])/hh[l] then c5:=-Valuation(delta2[l])/hh[l]; end if; end for;  c6:=0; if not IsEmpty(I) then l:=I[1]; max:=c1[l]/hh[l]; if Exp(2) gt max then max:=Exp(2); end if; c6:=2*(-Valuation(delta2[l])/hh[l] + max*Log(max)); for l in I do max:=c1[l]/hh[l]; if Exp(2) gt max then max:=Exp(2); end if; if 2*( -Valuation(delta2[l])/hh[l] + max*Log(max)) gt c6 then c6:=2*( -Valuation(delta2[l])/hh[l] + max*Log(max)); end if; end for; c6:=Ceiling(c6)-1; end if; c7:=2; if c4primeprime gt c7 then c7:=c4primeprime; end if;  162  c7:=Max([2,c4primeprime,c6]); //////////////////////////////////////////////////////////////////////// /* Compute c_{8}^{\prime}, c_{8}^{\prime \prime}, c_{9}^{\prime}, c_{9}^{\prime \prime} */ //////////////////////////////////////////////////////////////////////// min:=Abs(ImageOfalphaC[1]*ImageOfzetaC[1]); for i:=2 to n do if Abs(ImageOfalphaC[i]*ImageOfzetaC[i]) lt min then min:=Abs(ImageOfalphaC[i]*ImageOfzetaC[i]); end if; end for; c8prime:=Abs(a); for i:=1 to v do if i in J then c8prime:= c8prime*p[i]^(ss[i]+tt[i]); else c8prime:= c8prime*p[i]^(ss[i]+tt[i]+ValueOfn[i]*hh[i]); end if; end for; c8prime:=Log(c8prime/min); prod:=1; for i in J do l:=i; prod:=prod*ImageOfpiC[i][kk[i]][1]; end for; min:=Abs(prod); for ii:=2 to n do prod:=1; for i in J do l:=i; prod:=prod*ImageOfpiC[i][kk[i]][ii]; end for; 163  if Abs(prod) lt min then min:=Abs(prod); end if; end for; c9prime:=1; for i in J do c9prime:=c9prime*p[i]^hh[i]; end for; c9prime:=Log(c9prime/min); max:=Abs(ImageOfalphaC[1]*ImageOfzetaC[1]); for i:=2 to n do if Abs(ImageOfalphaC[i]*ImageOfzetaC[i]) gt max then max:=Abs(ImageOfalphaC[i]*ImageOfzetaC[i]); end if; end for; c8primeprime:=Log(max); prod:=1; for i in J do prod:=prod*ImageOfpiC[i][kk[i]][1]; end for; max:=Abs(prod); for ii:=2 to n do prod:=1; for i in J do prod:=prod*ImageOfpiC[i][kk[i]][ii]; end for; if Abs(prod) gt max then max:=Abs(prod); end if; end for; c9primeprime:=Log(max); ///////////////////////////////////////////////////////////////////////// /* If s > 0: For each i0 in {1,...,s}, compute the indices j=j(i0), k=k(i0), and the numbers c16=c16(i0), c17=c17(i0), c18=c18(i0). */ 164  ///////////////////////////////////////////////////////////////////////// jjjjjj:=[]; kkkkkk:=[]; c16:=[]; c17:=[]; c18:=[]; ///////////////////////////////////////////////////////////////////////// /* s >= 3 case */ ///////////////////////////////////////////////////////////////////////// if s ge 3 then sFFF:=Signature(FFF); //sFFF = number of real embeddings of \CC LogarithmicAlphaC:=[]; for i0i0i0:=1 to s do //////////////////////// /* Choose j,k and compute c16 */ ///////////////////////// max:=0; for j:=1 to s do if j eq i0i0i0 then continue j; end if; for k:=j+1 to s do if k eq i0i0i0 then continue k; end if; OneOverc16:=(Abs(thetaC[i0i0i0] - thetaC[j])/2) *(Abs(thetaC[k] - thetaC[i0i0i0])/Abs(thetaC[j] - thetaC[k])); if OneOverc16 gt max then max:=OneOverc16; jjjjjj[i0i0i0]:=j; kkkkkk[i0i0i0]:=k; end if; 165  end for; end for; c16[i0i0i0]:=1/max; /////////////////////// /* Select an embedding (sigma in Section 13) of FFF into the complex numbers by selecting a conjugate in \CC (phidot) of the generator of FFF (FFF.1). Find the images of the roots of g in \CC under this embedding: rootsofginC Embedding FFF into \RR will produce a smaller constant c17[i0i0i0]. Define kappa. */ /////////////////////// kappa:=1; if sFFF eq 0 then kappa:=2; end if; phidot:=Conjugates(FFF.1)[1]; rootsofginC:=[]; for i:=1 to n do rootsofginC[i]:=0*phidot; for ii:=1 to Degree(FFF) do rootsofginC[i]:=rootsofginC[i]+rootsofginFFF[i][ii]*phidot^(ii-1); end for; end for; //////////////////////// /* Find preimages in FFF of theta^{(i_0)}, theta^{(j)}, theta^{(k)} under the embedding sigma of FFF into \CC.  We choose not to use MAGMA’s bulit  in preimage-finder to avoid round-off errors. To find the preimage of theta^{(i_0)}, we actually find the index ii0 in 166  {1,...,n} such that sigma(thetaF[ii0]) = thetaC[i0i0i0]. Similarly for theta^{(j)}, theta^{(k)}. PreimageOfalphaj = preimage in FFF of \alpha^{(j)} under the embedding sigma of FFF into \CC PreimageOfzetaj = preimage in FFF of \zeta^{(j)} under the embedding sigma of FFF into \CC PreimageOfalphak = preimage in FFF of \alpha^{(k)} under the embedding sigma of FFF into \CC PreimageOfzetak = preimage in FFF of \zeta^{(k)} under the embedding sigma of FFF into \CC We also find the preimages of pi_{i}^{(j)}, pi_{i}^{(k)}, eps_{i}^{(j)}, eps_{i}^{(k)} */ ////////////////////////// //find preimage of \theta^{(i_0)} min:=Abs(thetaC[i0i0i0] - rootsofginC[1]); ii0:=1; for i:=2 to n do if Abs(thetaC[i0i0i0] - rootsofginC[i]) lt min then min:=Abs(thetaC[i0i0i0] - rootsofginC[i]); ii0:=i; end if; end for; //find preimage of \theta^{(j)} min:=Abs(thetaC[jjjjjj[i0i0i0]] - rootsofginC[1]); ijjj:=1; for i:=2 to n do if Abs(thetaC[jjjjjj[i0i0i0]] - rootsofginC[i]) lt min then min:=Abs(thetaC[jjjjjj[i0i0i0]] - rootsofginC[i]); 167  ijjj:=i; end if; end for; //find preimage of \theta^{(k)} min:=Abs(thetaC[kkkkkk[i0i0i0]] - rootsofginC[1]); ikkk:=1; for i:=2 to n do if Abs(thetaC[kkkkkk[i0i0i0]] - rootsofginC[i]) lt min then min:=Abs(thetaC[kkkkkk[i0i0i0]] - rootsofginC[i]); ikkk:=i; end if; end for; PreimageOfzetaj:=0; for i:= 1 to n do PreimageOfzetaj:=PreimageOfzetaj + zeta[i]*ImageOfIntegralBasisElementF[ijjj][i]; end for; //i PreimageOfalphaj:=0; for i:= 1 to n do PreimageOfalphaj:=PreimageOfalphaj + alpha[i]*ImageOfIntegralBasisElementF[ijjj][i]; end for; //i PreimageOfzetak:=0; for i:= 1 to n do PreimageOfzetak:=PreimageOfzetak + zeta[i]*ImageOfIntegralBasisElementF[ikkk][i]; end for; //i PreimageOfalphak:=0; for i:= 1 to n do PreimageOfalphak:=PreimageOfalphak + alpha[i]*ImageOfIntegralBasisElementF[ikkk][i]; end for; //i  168  /* Note that: preimage of pi_{i}^{(j)} = ImageOfpiF[i][kk[i]][ijjj] preimage of pi_{i}^{(k)} = ImageOfpiF[i][kk[i]][ikkk] preimage of eps_{i}^{(j)} = ImageOfepsF[i][ijjj] preimage of eps_{i}^{(k)} = ImageOfepsF[i][ikkk] */ /////////////////////////////////////// /* Define the alpha_i for i in J, construct L, and find the prime ideal of L corresponding to sigma (see Section 11). */ ////////////////////////////////////// alphaALGEBRAIC:=[FFF|]; for i:=1 to 1 + v + r do alphaALGEBRAIC[i]:=1; //initialize end for; alphaALGEBRAIC[1]:=(thetaF[ii0] - thetaF[ijjj] / thetaF[ii0] - thetaF[ikkk]) *(PreimageOfalphak/PreimageOfalphaj) *(PreimageOfzetak/PreimageOfzetaj); for i in J do alphaALGEBRAIC[1+i]:=ImageOfpiF[i][kk[i]][ikkk] /ImageOfpiF[i][kk[i]][ijjj]; end for; for i:=1 to r do alphaALGEBRAIC[1+v+i]:=ImageOfepsF[i][ikkk]/ImageOfepsF[i][ijjj]; end for; LL:=sub<FFF | alphaALGEBRAIC>; d:=Degree(LL); mm:=1+#J+r; //////////////////////////////////// 169  /* Compute c17. Also compute the alpha_i as defined in Sections 18 and 20: LogarithmicAlphaC[i0i0i0][i] */ ///////////////////////////////////// LogarithmicAlphaC[i0i0i0]:=[RealField() | ]; for i:=1 to 1+v + r do LogarithmicAlphaC[i0i0i0][i]:=0; end for;  temp:=((thetaC[i0i0i0] - thetaC[jjjjjj[i0i0i0]]) /(thetaC[i0i0i0] - thetaC[kkkkkk[i0i0i0]])) *(ImageOfzetaC[kkkkkk[i0i0i0]]/ImageOfzetaC[jjjjjj[i0i0i0]]) *(ImageOfalphaC[kkkkkk[i0i0i0]]/ImageOfalphaC[jjjjjj[i0i0i0]]); LogarithmicAlphaC[i0i0i0][1]:=Log(Abs(temp)); H:=Max( [d*AbsoluteLogarithmicHeight(alphaALGEBRAIC[1]), Abs(Log(Abs(temp))), 0.16] ); for i in J do temp:=ImageOfpiC[i][kk[i]][kkkkkk[i0i0i0]] /ImageOfpiC[i][kk[i]][jjjjjj[i0i0i0]]; LogarithmicAlphaC[i0i0i0][1+i]:=Log(Abs(temp)); H:=H*Max( [d*AbsoluteLogarithmicHeight(alphaALGEBRAIC[1+i]), Abs(Log(Abs(temp))), 0.16] ); end for; for i:=1 to r do temp:=ImageOfepsC[i][kkkkkk[i0i0i0]]/ImageOfepsC[i][jjjjjj[i0i0i0]]; LogarithmicAlphaC[i0i0i0][1+v+i]:=Log(Abs(temp)); H:=H*Max( [d*AbsoluteLogarithmicHeight(alphaALGEBRAIC[1+v+i]), Abs(Log(Abs(temp))), 0.16] ); end for; 170  c17[i0i0i0]:= Min([(1/kappa)*((Exp(1)*mm/2)^(kappa))*(30^(mm+3))*(mm^(3.5)), (2^(6*mm+20))])*(d^2)*(1+Log(d))*H; ////////////////////////////// /* Compute c18 */ ////////////////////////////// c18[i0i0i0]:= Log(2*Log(2)*c16[i0i0i0]) + c17[i0i0i0]; end for; //end i0i0i0 loop end if; //////////////////////////////////////////////////////////////////////// /* s=1,2 case */ //////////////////////////////////////////////////////////////////////// if s eq 1 or s eq 2 then sFFF:=Signature(FFF); //sFFF = number of real embeddings of \CC LogarithmicAlphaC:=[]; for i0i0i0:=1 to s do //////////////////////// /* Choose j,k and compute c16 */ ///////////////////////// max:=0; for i:=1 to t do 171  j:=s-1 + 2*i; k:=j+1; OneOverc16:=(Abs(thetaC[i0i0i0] - thetaC[j])/2)* (Abs(thetaC[k] - thetaC[i0i0i0])/Abs(thetaC[j] - thetaC[k])); if OneOverc16 gt max then max:=OneOverc16; jjjjjj[i0i0i0]:=j; kkkkkk[i0i0i0]:=k; end if; end for; c16[i0i0i0]:=1/max; /////////////////////// /* Select an embedding (sigma in Section 13) of FFF into the complex numbers by selecting a conjugate in \CC (phidot) of the generator of FFF (FFF.1). Find the images of the roots of g in \CC under this embedding: rootsofginC Embedding FFF into \CC will produce a smaller constant c17[i0i0i0]. Define kappa. */ /////////////////////// kappa:=1; if sFFF eq 0 then kappa:=2; end if; phidot:=Conjugates(FFF.1)[1]; rootsofginC:=[]; for i:=1 to n do rootsofginC[i]:=0*phidot; for ii:=1 to Degree(FFF) do rootsofginC[i]:=rootsofginC[i]+rootsofginFFF[i][ii]*phidot^(ii-1); end for; end for; 172  //////////////////////// /* Find preimages in FFF of theta^{(i_0)}, theta^{(j)}, theta^{(k)} under the embedding sigma of FFF into \CC.  We choose not to use MAGMA’s bulit  in preimage-finder to avoid round-off errors. To find the preimage of theta^{(i_0)}, we actually find the index ii0 in {1,...,n} such that sigma(thetaF[ii0]) = thetaC[i0i0i0]. Similarly for theta^{(j)}, theta^{(k)}. PreimageOfalphaj = preimage in FFF of \alpha^{(j)} under the embedding sigma of FFF into \CC PreimageOfzetaj = preimage in FFF of \zeta^{(j)} under the embedding sigma of FFF into \CC PreimageOfalphak = preimage in FFF of \alpha^{(k)} under the embedding sigma of FFF into \CC PreimageOfzetak = preimage in FFF of \zeta^{(k)} under the embedding sigma of FFF into \CC We also find the preimages of pi_{i}^{(j)}, pi_{i}^{(k)}, eps_{i}^{(j)}, eps_{i}^{(k)} */ ////////////////////////// //find preimage of \theta^{(i_0)} min:=Abs(thetaC[i0i0i0] - rootsofginC[1]); ii0:=1; for i:=2 to n do if Abs(thetaC[i0i0i0] - rootsofginC[i]) lt min then min:=Abs(thetaC[i0i0i0] - rootsofginC[i]); ii0:=i; end if; 173  end for; //find preimage of \theta^{(j)} min:=Abs(thetaC[jjjjjj[i0i0i0]] - rootsofginC[1]); ijjj:=1; for i:=2 to n do if Abs(thetaC[jjjjjj[i0i0i0]] - rootsofginC[i]) lt min then min:=Abs(thetaC[jjjjjj[i0i0i0]] - rootsofginC[i]); ijjj:=i; end if; end for; //find preimage of \theta^{(k)} min:=Abs(thetaC[kkkkkk[i0i0i0]] - rootsofginC[1]); ikkk:=1; for i:=2 to n do if Abs(thetaC[kkkkkk[i0i0i0]] - rootsofginC[i]) lt min then min:=Abs(thetaC[kkkkkk[i0i0i0]] - rootsofginC[i]); ikkk:=i; end if; end for; PreimageOfzetaj:=0; for i:= 1 to n do PreimageOfzetaj:=PreimageOfzetaj + zeta[i]*ImageOfIntegralBasisElementF[ijjj][i]; end for; //i PreimageOfalphaj:=0; for i:= 1 to n do PreimageOfalphaj:=PreimageOfalphaj + alpha[i]*ImageOfIntegralBasisElementF[ijjj][i]; end for; //i PreimageOfzetak:=0; for i:= 1 to n do PreimageOfzetak:=PreimageOfzetak 174  + zeta[i]*ImageOfIntegralBasisElementF[ikkk][i]; end for; //i PreimageOfalphak:=0; for i:= 1 to n do PreimageOfalphak:=PreimageOfalphak + alpha[i]*ImageOfIntegralBasisElementF[ikkk][i]; end for; //i /* Note that: preimage of pi_{i}^{(j)} = ImageOfpiF[i][kk[i]][ijjj] preimage of pi_{i}^{(k)} = ImageOfpiF[i][kk[i]][ikkk] preimage of eps_{i}^{(j)} = ImageOfepsF[i][ijjj] preimage of eps_{i}^{(k)} = ImageOfepsF[i][ikkk] */ /////////////////////////////////////// /* Define the alpha_i for i in J, construct L, and find the prime ideal of L corresponding to sigma (see Section 11). */ ////////////////////////////////////// alphaALGEBRAIC:=[FFF|]; for i:=1 to 1 + v + r do alphaALGEBRAIC[i]:=1; //initialize end for; alphaALGEBRAIC[1]:=(thetaF[ii0] - thetaF[ijjj] / thetaF[ii0] - thetaF[ikkk])*(PreimageOfalphak/PreimageOfalphaj) *(PreimageOfzetak/PreimageOfzetaj); for i in J do alphaALGEBRAIC[1+i]:=ImageOfpiF[i][kk[i]][ikkk] /ImageOfpiF[i][kk[i]][ijjj]; end for; for i:=1 to r do alphaALGEBRAIC[1+v+i]:=ImageOfepsF[i][ikkk]/ImageOfepsF[i][ijjj]; 175  end for; LL:=sub<FFF | alphaALGEBRAIC>; d:=Degree(LL); mm:=2+#J+r;  //////////////////////////////////// /* Compute c17. Also compute the alpha_i as defined in Sections 18 and 20: LogarithmicAlphaC[i0i0i0][i] */ ///////////////////////////////////// LogarithmicAlphaC[i0i0i0]:=[RealField() | ]; for i:=1 to 1+v + r do LogarithmicAlphaC[i0i0i0][i]:=0; end for;  temp:=((thetaC[i0i0i0] - thetaC[jjjjjj[i0i0i0]]) /(thetaC[i0i0i0] - thetaC[kkkkkk[i0i0i0]])) *(ImageOfzetaC[kkkkkk[i0i0i0]]/ImageOfzetaC[jjjjjj[i0i0i0]]) *(ImageOfalphaC[kkkkkk[i0i0i0]]/ImageOfalphaC[jjjjjj[i0i0i0]]); LogarithmicAlphaC[i0i0i0][1]:=Imaginary(Log(temp)); H:=Max( [d*AbsoluteLogarithmicHeight(alphaALGEBRAIC[1]), Abs(Log(temp)), 0.16] ); for i in J do temp:=ImageOfpiC[i][kk[i]][kkkkkk[i0i0i0]] /ImageOfpiC[i][kk[i]][jjjjjj[i0i0i0]]; LogarithmicAlphaC[i0i0i0][1+i]:=Imaginary(Log(temp)); H:=H*Max( [d*AbsoluteLogarithmicHeight(alphaALGEBRAIC[1+i]), Abs(Log(temp)), 0.16] ); 176  end for; for i:=1 to r do temp:=ImageOfepsC[i][kkkkkk[i0i0i0]]/ImageOfepsC[i][jjjjjj[i0i0i0]]; LogarithmicAlphaC[i0i0i0][1+v+i]:=Imaginary(Log(temp)); H:=H*Max( [d*AbsoluteLogarithmicHeight(alphaALGEBRAIC[1+v+i]), Abs(Log(temp)), 0.16] ); end for; LogarithmicAlphaC[i0i0i0][2+v+r]:=PI; // = Im Log(-1) H:=H*Max([d*0, PI, 0.16]); //AbsoluteLogarithmicHeight(-1) = 0 c17[i0i0i0]:= Min([(1/kappa)*((Exp(1)*mm/2)^(kappa))*(30^(mm+3))*(mm^(3.5)), (2^(6*mm+20))])*(d^2)*(1+Log(d))*H;  ////////////////////////////// /* Compute c18 */ ////////////////////////////// c18[i0i0i0]:= Log(4*Arcsin(1/4)*c16[i0i0i0]) + c17[i0i0i0] + c17[i0i0i0]*Log(#JJJ);  end for; //end i0i0i0 loop end if; ///////////////////////////////////////////////////////////////////////// /* Done computing the indices j=j(i0), k=k(i0), and the numbers c16=c16(i0), c17=c17(i0), c18=c18(i0) for every i0 in {1,...,s} (when s > 0) 177  */ ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// //////////////////////////////////////// /////////////////// /* Choose c11 to minimize the value of c22, the upper bound for H.  In the  process, compute the constants that depend on c11: c11, c12, c13, c14, c15, c19, c20, c21, c22 */ ////////////////// //////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// if s gt 0 then c11:=(1/1000000)*c10/(n-1); c12prime:=(c8prime + c5*c9prime)/(c10 - (n-1)*c11); c13prime:=c4*c9prime/(c10 - (n-1)*c11); if c13prime lt Exp(2) then c13prime:=Exp(2); end if; c12primeprime:=(c8primeprime + c5*c9primeprime)/(c10 - c11); c13primeprime:=c4*c9primeprime/(c10 - c11); if c13primeprime lt Exp(2) then c13primeprime:=Exp(2); end if; c14:=2*Ceiling(c12prime + c13prime*Log(c13prime))-1; if c14 lt 2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1 then c14:=2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1; end if; if c14 lt 2 then c14:=2; end if; c15:=0; if t gt 0 then 178  min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; c19:=Ceiling(Log(2*c16[1])/c11)-1; max1:=c17[1]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[1]/c11) + max1*Log(max1) ); for i0i0i0:=2 to s do c19:=Ceiling(Log(2*c16[i0i0i0])/c11)-1; max1:=c17[i0i0i0]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[i0i0i0]/c11) + max1*Log(max1) ); end for; c20:=Ceiling(c20)-1; c21:=Max([c15,c19,c20,1]); c22:=Max([c7,c14,c21]); //// c11:=((1000000 - 1)/1000000)*c10/(n-1); c12prime:=(c8prime + c5*c9prime)/(c10 - (n-1)*c11); c13prime:=c4*c9prime/(c10 - (n-1)*c11); if c13prime lt Exp(2) then c13prime:=Exp(2); end if; c12primeprime:=(c8primeprime + c5*c9primeprime)/(c10 - c11); c13primeprime:=c4*c9primeprime/(c10 - c11); if c13primeprime lt Exp(2) then c13primeprime:=Exp(2); end if; 179  c14:=2*Ceiling(c12prime + c13prime*Log(c13prime))-1; if c14 lt 2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1 then c14:=2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1; end if; if c14 lt 2 then c14:=2; end if; c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; c19:=Ceiling(Log(2*c16[1])/c11)-1; max1:=c17[1]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[1]/c11) + max1*Log(max1) ); for i0i0i0:=2 to s do c19:=Ceiling(Log(2*c16[i0i0i0])/c11)-1; max1:=c17[i0i0i0]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[i0i0i0]/c11) + max1*Log(max1) ); end for; c21:=Max([c15,c19,c20,1]); if Max([c7,c14,c21]) gt c22 then c22:=Max([c7,c14,c21]); end if; //// 180  for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); c12prime:=(c8prime + c5*c9prime)/(c10 - (n-1)*c11); c13prime:=c4*c9prime/(c10 - (n-1)*c11); if c13prime lt Exp(2) then c13prime:=Exp(2); end if; c12primeprime:=(c8primeprime + c5*c9primeprime)/(c10 - c11); c13primeprime:=c4*c9primeprime/(c10 - c11); if c13primeprime lt Exp(2) then c13primeprime:=Exp(2); end if; c14:=2*Ceiling(c12prime + c13prime*Log(c13prime))-1; if c14 lt 2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1 then c14:=2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1; end if; if c14 lt 2 then c14:=2; end if; c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; c19:=Ceiling(Log(2*c16[1])/c11)-1; max1:=c17[1]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[1]/c11) + max1*Log(max1) ); for i0i0i0:=2 to s do 181  c19:=Ceiling(Log(2*c16[i0i0i0])/c11)-1; max1:=c17[i0i0i0]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[i0i0i0]/c11) + max1*Log(max1) ); end for; c21:=Max([c15,c19,c20,1]); if Max([c7,c14,c21]) gt c22 then c22:=Max([c7,c14,c21]); end if; end for; //end i //////////////////////////////////////////////////////////////// else //s = 0 /////////////////////////////////////////////////////////////// c11:=(1/1000000)*c10/(n-1); c12prime:=(c8prime + c5*c9prime)/(c10 - (n-1)*c11); c13prime:=c4*c9prime/(c10 - (n-1)*c11); if c13prime lt Exp(2) then c13prime:=Exp(2); end if; c12primeprime:=(c8primeprime + c5*c9primeprime)/(c10 - c11); c13primeprime:=c4*c9primeprime/(c10 - c11); if c13primeprime lt Exp(2) then c13primeprime:=Exp(2); end if; c14:=2*Ceiling(c12prime + c13prime*Log(c13prime))-1; if c14 lt 2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1 then c14:=2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1; end if; if c14 lt 2 then c14:=2; end if; c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); 182  for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; c19:=Ceiling(Log(2*c16[1])/c11)-1; max1:=c17[1]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[1]/c11) + max1*Log(max1) ); for i0i0i0:=2 to s do c19:=Ceiling(Log(2*c16[i0i0i0])/c11)-1; max1:=c17[i0i0i0]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[i0i0i0]/c11) + max1*Log(max1) ); end for; c21:=Max([c15,c19,c20,1]); c22:=Max([c7,c14,c21]); //// c11:=((1000000 - 1)/1000000)*c10/(n-1); c12prime:=(c8prime + c5*c9prime)/(c10 - (n-1)*c11); c13prime:=c4*c9prime/(c10 - (n-1)*c11); if c13prime lt Exp(2) then c13prime:=Exp(2); end if; c12primeprime:=(c8primeprime + c5*c9primeprime)/(c10 - c11); c13primeprime:=c4*c9primeprime/(c10 - c11); if c13primeprime lt Exp(2) then c13primeprime:=Exp(2); end if; c14:=2*Ceiling(c12prime + c13prime*Log(c13prime))-1; 183  if c14 lt 2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1 then c14:=2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1; end if; if c14 lt 2 then c14:=2; end if; c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; c19:=Ceiling(Log(2*c16[1])/c11)-1; max1:=c17[1]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[1]/c11) + max1*Log(max1) ); for i0i0i0:=2 to s do c19:=Ceiling(Log(2*c16[i0i0i0])/c11)-1; max1:=c17[i0i0i0]/c11; if max1 lt Exp(2) then max1:=Exp(2); end if; c20:=2*( (c18[i0i0i0]/c11) + max1*Log(max1) ); end for; c21:=Max([c15,c19,c20,1]); if Max([c7,c14,c21]) gt c22 then c22:=Max([c7,c14,c21]); end if; //// for i:=1 to 999 do 184  c11:=(i/1000)*c10/(n-1); c12prime:=(c8prime + c5*c9prime)/(c10 - (n-1)*c11); c13prime:=c4*c9prime/(c10 - (n-1)*c11); if c13prime lt Exp(2) then c13prime:=Exp(2); end if; c12primeprime:=(c8primeprime + c5*c9primeprime)/(c10 - c11); c13primeprime:=c4*c9primeprime/(c10 - c11); if c13primeprime lt Exp(2) then c13primeprime:=Exp(2); end if; c14:=2*Ceiling(c12prime + c13prime*Log(c13prime))-1; if c14 lt 2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1 then c14:=2*Ceiling(c12primeprime + c13primeprime*Log(c13primeprime))-1; end if; if c14 lt 2 then c14:=2; end if; c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; if Max([c7,c14,c15]) gt c22 then c22:=Max([c7,c14,c15]); end if; end for; //end i end if; //////////////////////////////////////////////////////////////////////// 185  /* UpperBoundForH:= current best upper bound for H = H_0 from Section 15. UpperBoundForA:= current best upper bound for A = A_0 from Section 15. ConditionalUpperBoundForA[i0]:= current best i_0-conditonal upper bound for A = A_0(i_0) from Section 19. UpperBoundForn[l]:= current best upper bound for n_l = N_l from Section 15. UpperBoundForN:= current best upper bound for N For l in I2, N_{l}^{*} bounds n_l. For l in I, we use Corollary 14.2. B[i]:= current best upper bound for |b_i| = B_i from section 15. */ ////////////////////////////////////////////////////////////////////////// UpperBoundForn:=[]; ConditionalUpperBoundForA:=[]; UpperBoundForH:=c22; UpperBoundForA:=UpperBoundForH; for i0:=1 to s do ConditionalUpperBoundForA[i0]:=UpperBoundForA; end for; for l:=1 to v do UpperBoundForn[l]:=1; //initialize end for; for l in I2 do UpperBoundForn[l]:=Nstar[l]; end for; for l in I do UpperBoundForn[l]:= 186  Ceiling( (c1[l]/hh[l])*Log(c22) - (1/hh[l])*Valuation(delta2[l]) ) - 1; if 2 gt UpperBoundForn[l] then UpperBoundForn[l]:=2; end if; if c22 lt UpperBoundForn[l] then UpperBoundForn[l]:=c22; end if; end for; UpperBoundForN:=Max(UpperBoundForn); B:=[]; for i:=1 to 1+v+r do B[i]:=0; //initialize end for; B[1]:=1; for i in J do B[1+i]:=UpperBoundForn[i]; end for; for i:=1 to r do B[1+v+i]:=UpperBoundForA; end for; ///////////////////////////////////////////// /* If UpperBoundForA < 0, then we know there are no solutions for the current case of (11). If UpperBoundForn[i] < 0 for some i in J, then we know there are no solutions for the current case of (11). */ ///////////////////////////////////////////// print("Starting basic reduction procedures."); ///////////////////////////////////////////////////////////////////////// ////////////////////// /* Start Of Loop For Repeated Simple Reductions 187  */ /////////////////////// /////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// Improvement:=true; while Improvement do Improvement:=false; //////////////////////////////////////////////////////////////////////// /* Basic p_l-adic reduction for each l in I (Section 18) */ /////////////////////////////////////////////////////////////////////// for l in I do //print("basic p_l, l="); //l; //////////////////////////////////////////////////////////////////////// /* Define: W[i] = W_i (weights) for p_l (Section 18) QQ = Q (Section 18) mmmm = m for p_l (Section 18) Initialize: betam[i] = beta_i^(m) for p[L], Tm, where Transpose(Tm) = U_m from Section 18 */ ///////////////////////////////////////////////////////////////////////// W:=[]; for i:=1 to 1+v+r do W[i]:=0; //initialize end for; 188  W[1]:=0; for i:=2 to #JJJ do W[JJJ[i]]:=RoundP(UpperBoundForH/B[JJJ[#JJJ]]); end for; //print("weights:"); //W; //print("B"); //B; QQ:=0; for i in JJJ do QQ:=QQ+(W[i]^2)*(B[i]^2); //recall W[1]=0 end for; prod:=1; for i:=2 to #JJJ do prod:=prod*W[JJJ[i]]; end for; /* mmmm:=Ceiling( ( (#JJJ - 1)/(2*Log(p[l])) )*Log( 2^(#JJJ - 1) * QQ / prod^(2/(#JJJ - 1)) ) ); */ mmmm:=Ceiling( ( (#JJJ - 1)/(2*Log(p[l])) )*Log( QQ / prod^(2/(#JJJ - 1)) ) ); betam:=[]; for i:=1 to 1+v+r do betam[i]:=0; end for; 189  Tm:=ScalarMatrix(IntegerRing(),#JJJ-1,1); /*initialize as #JJJ-1 by #JJJ-1 identity matrix*/ //////////////////////////////////////////////////////////////////////// /* Start while loop that will increase m until the p_l-adic reduction yeilds a new upper bound for n_l or until a number of increases has been made with no success */ //////////////////////////////////////////////////////////////////////// flag:=true; RunThroughNumber:=0; while flag do //print("RunThroughNumber"); //RunThroughNumber; ///////////////////////////////////////////////////////////////////////// /* Increase mmmm = m (if this is not the first attempt with the basic p_l-reduction procedure). Calculuate betam[i] = beta_i^(m). */ /////////////////////////////////////////////////////////////////////// mmmm:=Ceiling( mmmm + (RunThroughNumber/20)*mmmm ); //print("mmmm"); //mmmm; if mmmm gt (0.95)*padicprecision[l] then PadicPrecisionMultiplier[l] := PadicPrecisionMultiplier[l] + 1; continue PrecisionLoopVariable; end if; for i in JJJ do betam[i]:= SmallestNonnegativeRemainderModpLToThem(beta[l][i],l,mmmm); 190  end for; ///////////////////////////////////////////////////////////////////////// /* Define: Am = A_m for p[L] Gamma_m = lattice generated by columns of A_m */ /////////////////////////////////////////////////////////////////////////  Am:=ZeroMatrix(IntegerRing(), v+r+2, v+r+2); for i:=1 to v+r+1 do Am[i][i]:=W[i]; end for; for j:=1 to v+r+1 do Am[v+r+2][j]:=W[ihat[l]]*betam[j]; end for; Am[v+r+2][v+r+2]:=W[ihat[l]]*p[l]^mmmm; for i:=1+v+r to 2 by -1 do if i eq ihat[l] or not i in JJJ then RemoveColumn(~Am,i); RemoveRow(~Am,i); end if; end for; RemoveColumn(~Am,1); RemoveRow(~Am,1); //Am is now a #JJJ-1 by #JJJ-1 matrix Am:=Am*Transpose(Tm); //Transpose(Tm) = Um from Setion 15 /* If this is the first run through, Tm is the identity. If this is not the first run through, this will save computation time. 191  */  ///////////////////////////////////////////////////////////////////////// /* Compute an LLL reduced basis for the lattice Gamma_m generated by columns of A_m.  The algorithm used is de Weger’s exact integer version of LLL.  Note: LLL(X) assumes ROWS of X span the lattice, so we need to feed it the transpose of A_m.  Similarly, it spits out the transpose of B_m and  the transpose of U_m */ ///////////////////////////////////////////////////////////////////////// //time temp,Tm,rank:=LLL( Transpose(Am) : Proof:=true, Method:="Integral", Delta:=0.75, Eta:=0.5 ); Bm:=MatrixRing(RationalField(),#JJJ-1) ! Transpose(temp); //columns are LLL-reduced basis for Gamma_m /* Here Tm*Transpose(Am) = Transpose(Bm). So with Um=Transpose(Tm) we have Am*Um = Bm, and With Vm = Bm*Transpose(Tm)*Bm^(-1) = Am*Transpose(Tm)*Am^(-1), we have Vm*Am = Bm. */ //////////////////////////////////////////////////////////////////////// /* Compute the lower bound for l(Gamma_m,y) using Lemma 16.1.  If it is  large enough (bigger than sqrt(Q)), compute the new upper bound for n[L].  Otherwise, increase m and reduce again (go back to the start of  the while loop). 192  */ ///////////////////////////////////////////////////////////////////////// lowerbound:=0; //START IF if betam[1] eq 0 then //y = 0 case (vectors) //c1 = Transpose(Bm)[1] lowerbound:= 2^(-(#JJJ-2)/2)*Norm(Transpose(Bm)[1])^(1/2); else  //y neq 0 case  yyy:=ZeroMatrix(RationalField(),#JJJ-1,1); yyy[#JJJ-1][1]:=-W[ihat[l]]*betam[1]; sss:=(Bm^(-1))*yyy; IndicesjWithsjNotIntegral:=[]; for j:=1 to #JJJ-1 do if not IsIntegral(sss[j][1]) then Append(~IndicesjWithsjNotIntegral,j); end if; end for; delta:=[RealField() | ]; for j:=1 to #JJJ-2 do delta[j]:=0; for i:=j+1 to #JJJ-1 do if delta[j] lt DistanceToNearestInteger(sss[i][1])*Norm(Transpose(Bm)[i])^(1/2) then delta[j]:= DistanceToNearestInteger(sss[i][1])*Norm(Transpose(Bm)[i])^(1/2); end if; end for; end for; delta[#JJJ-1]:=0; 193  max:=0; for j in IndicesjWithsjNotIntegral do if max lt 2^(-(#JJJ-2)/2) * DistanceToNearestInteger(sss[j][1]) * Norm(Transpose(Bm)[1])^(1/2) - (#JJJ - 1 - j)*delta[j] then max:=2^(-(#JJJ-2)/2) * DistanceToNearestInteger(sss[j][1]) * Norm(Transpose(Bm)[1])^(1/2) - (#JJJ - 1 - j)*delta[j]; end if; end for; lowerbound:=max; end if; //END IF if lowerbound gt QQ^(1/2) then flag:=false; //ready to get out of while loop that increases m if //necessary OldUpperBoundFornl:=UpperBoundForn[l]; NewUpperBoundFornl:= Max([ Floor( (1/hh[l])*(1/(p[l] - 1) - Valuation(delta2[l])) ), Ceiling((1/hh[l])*(mmmm-dd[l]))-1, 0 ]); if NewUpperBoundFornl lt OldUpperBoundFornl then Improvement:=true; UpperBoundForn[l]:=NewUpperBoundFornl; B[1+l]:=UpperBoundForn[l]; end if;  194  else RunThroughNumber+:=1;  //increase m and try again  /// /* If increasing m 20 times (in which case m will be double its original value) fails to produce a new upper bound for n_l, move onto the next value of l in I.  Also, print a message indicating that the basic  p_l-adic reduction procedure was unsuccesful. */ ///// if RunThroughNumber eq 20 then print("Basic p-adic reduction taking too long"); print("Case:"); iiii; print("l:"); l; continue l; end if; end if; /* IF controlled by lowerbound gt QQ^(1/2) */ end while; /*this is the loop that increases m if necessary, the while loop controlled by flag*/ if UpperBoundForn[l] lt 0 then //there are no solutions of the current case of (11) continue iiii; end if; end for; // end l loop UpperBoundForN:=Max(UpperBoundForn); /* print("Starting basic real reduction"); 195  print("Log_10 of Upper Bound For A"); Log(UpperBoundForA)/Log(10); */ ///////////////////////////////////////////////////////////////////////// /* Basic Real Reduction (Section 19) */ ///////////////////////////////////////////////////////////////////////// for i0:=1 to s do ConditionalUpperBoundForA[i0]:=UpperBoundForA; end for; ///////////////////////////////////////////////////////////////////////// /* Totally Complex Case, i.e, s=0 */ ///////////////////////////////////////////////////////////////////////// if s eq 0 then //Choose c11 to find an choose optimal upper bound for A from Lemma 19.1 MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); c15:=0; min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; 196  if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 with a certain value of //c11 if max lt MIN then MIN:=max; end if; c11:=((1000000 - 1)/1000000)*c10/(n-1); c15:=0; min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 with a certain value of //c11 if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1);  197  c15:=0; min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 with a certain value of //c11 if max lt MIN then MIN:=max; end if; end for;  //end i loop  OldUpperBoundForA:=UpperBoundForA; NewUpperBoundForA:=MIN;  if NewUpperBoundForA lt OldUpperBoundForA then Improvement:=true; UpperBoundForA:=NewUpperBoundForA; end if; else //s > 0 ///////////////////////////////////////////////////////////////////////// /* s>0 Case */ 198  ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// /* Real Case, i.e., s \geq 3 */ ///////////////////////////////////////////////////////////////////////// if s ge 3 then // s>=3 real case JumpToEndOfRealReduction:=false; for i0:=1 to s do //print("basic real, i0="); //i0; ////////////////////////////////////////////////////////////////////////// /* Define weights W[i] (Section 19) R (Section 19) S (Section 19) CCCCCC = C (Section 19) Initialize: TC, where Transpose(TC) = U_C from Section 19 phi[i]:= phi_i from Section 19 */ ///////////////////////////////////////////////////////////////////////// W:=[]; for i:=1 to 1+v+r do W[i]:=0; //initialize end for; H0prime:=0; for i:=2 to #JJJ-1 do if H0prime lt B[JJJ[i]] then H0prime:=B[JJJ[i]]; end if; 199  end for; W[1]:=0; for i:=2 to #JJJ-1 do W[JJJ[i]]:=RoundP(H0prime/B[JJJ[i]]); end for; //print("weights"); //W; //print("B"); //B; R:=0; for i in JJJ do R:=R + B[i]; end for; R:=(1/2)*R; //this is just an approximation to R S:=0; for i:=2 to #JJJ-1 do S:=S+(W[JJJ[i]]^2)*(B[JJJ[i]]^2); end for; prod:=1; for i:=2 to #JJJ-1 do prod:=prod*W[JJJ[i]]; end for; /* LogC:= ((#JJJ-1)/2)*Log( (R^2 + S) / ( 2^(-(#JJJ-1)) * (Abs(LogarithmicAlphaC[i0][JJJ[#JJJ]])*prod)^(2/(#JJJ-1)) ) ); */  200  LogC:= ((#JJJ-1)/2)*Log( (R^2 + S) / ( 2^(-2*(#JJJ-1)) * (Abs(LogarithmicAlphaC[i0][JJJ[#JJJ]])*prod)^(2/(#JJJ-1)) ) );  /* LogC/Log(10); LogC:=430; LogC := ((#JJJ-1)/2)*Log((#JJJ-1) * Max([UpperBoundForA,Max(UpperBoundForn)])^2); LogC/Log(10); break iiii; */  //CCCCCC:=Ceiling(Exp(LogC));  TC:=ScalarMatrix(IntegerRing(),#JJJ-1,1); //#JJJ-1 by #JJJ-1 identity matrix phi:=[]; for i:=1 to 1+v+r do phi[i]:=0; end for; //////////////////////////////////////////////////////////////////////// /* Start the while loop where C will be increased until a new conditional upper for A is found that improves on the uncondtional upper bound for A 201  or until a number of increases of C have been made with no success. */ //////////////////////////////////////////////////////////////////////// RunThroughNumber1:=0; RunThroughNumber2:=0; flag:=true; while flag do  ///////////////////////////////////////////////////////////////////////// /* Increase CCCCCC = C (if this is not the first attempt the basic real reduction procedure). Calculate the phi_i for i in JJJ. Calculate R. */ //////////////////////////////////////////////////////////////////////// CCCCCC:= Ceiling(Exp(LogC + ((RunThroughNumber1 + RunThroughNumber2)/20)*LogC)); if RunThroughNumber1 eq 21 and UpperBoundForA gt 100000 then CCCCCC:=Ceiling(Exp(LogC + 9*LogC)); end if; if RunThroughNumber1 eq 22 and UpperBoundForA gt 100000 then CCCCCC:=Ceiling(Exp(LogC + 9*LogC)); end if; if LogC/Log(10) gt (0.95)*realprecision then RealPrecisionMultiplier := RealPrecisionMultiplier + 1; continue PrecisionLoopVariable; end if; //print("Log_10 (C)"); //Floor(LogC/Log(10)); 202  for i in JJJ do phi[i]:=Round(CCCCCC*LogarithmicAlphaC[i0][i]); end for; phi[1]:=Round(CCCCCC*LogarithmicAlphaC[i0][1]); if Abs(phi[JJJ[#JJJ]]) lt 2 then if CCCCCC*LogarithmicAlphaC[i0][JJJ[#JJJ]] ge 0 then phi[JJJ[#JJJ]]:=2; else phi[JJJ[#JJJ]]:=-2; end if; end if; if IsIntegral(phi[1]/phi[JJJ[#JJJ]]) then if Abs(phi[1]+1 - CCCCCC*LogarithmicAlphaC[i0][1]) le 1 then phi[1]:=phi[1]+1; else phi[1]:=phi[1]-1; end if; end if; R:=0; for i in JJJ do R:=R + B[i]*Abs( CCCCCC*LogarithmicAlphaC[i0][i] -  phi[i] );  end for; ///////////////////////////////////////////////////////////////////////// /* Compute: AC = A_C */ ///////////////////////////////////////////////////////////////////////// AC:=ZeroMatrix(IntegerRing(),v+r+1,v+r+1);  203  for i:=1 to v+r do AC[i][i]:=W[i]; end for; for j:=1 to v+r+1 do AC[v+r+1][j]:=phi[j]; end for; for i:=1+v+r to 2 by -1 do if not i in JJJ then RemoveColumn(~AC,i); RemoveRow(~AC,i); end if; end for; RemoveRow(~AC,1); RemoveColumn(~AC,1); //AC is now a #JJJ-1 by #JJJ-1 matrix AC:=AC*Transpose(TC); /* If this is the first run through Transpose(TC) is the identity. Otherwise Transpose(TC) is UC.  This will time in the LLL reduction. */  //print("AC[#JJJ-1]:"); //AC[#JJJ-1]; //////////////////////////////////////////////////////////////////////// /* Compute LLL reduced basis for the lattice Gamma_C generated by columns of A_C.  The algoritm used is de Weger’s exact integer version of LLL.  Note: LLL(X) assumes ROWS of X span the lattice, so we need to feed it the transpose of A_C.  Similarly, it spits out the transpose of B_C and  the transpose of U_C */ ///////////////////////////////////////////////////////////////////////// 204  //time temp,TC,rank:=LLL(Transpose(AC) : Proof:=true, Method:="Integral", Delta:=0.75, Eta:=0.5 ); BC:=MatrixRing(RationalField(),#JJJ-1) ! Transpose(temp); //columns are LLL-reduced basis for Gamma_C /* Here TC*Transpose(AC) = Transpose(BC). So with UC=Transpose(TC) we have AC*UC = BC, and With VC = BC*Transpose(TC)*BC^(-1) = AC*Transpose(TC)*AC^(-1), we have VC*AC = BC. */ ///////////////////////////////////////////////////////////////////////// /* Compute the lower bound for l(Gamma_C,y).  If it is large enough  (bigger than sqrt(R^2 + S)), compute the new upper bound for n[L]. Otherwise, increase C and reduce again (go back to the start of the while loop) */ ///////////////////////////////////////////////////////////////////////// //START IF if phi[1] eq 0 then //y = 0 case (vectors) //never happens by choice of phi[1] // \vec{c}_1 = Transpose(BC)[1] lowerbound:= 2^(-(#JJJ-2)/2)*Norm( Transpose(BC)[1] )^(1/2); print("lowerbound, y=0:"); lowerbound; else  //y neq 0 case  yyy:=ZeroMatrix(RationalField(),#JJJ-1,1); 205  yyy[#JJJ-1][1]:=-phi[1]; sss:=(BC^(-1))*yyy; IndicesjWithsjNotIntegral:=[]; for j:=1 to #JJJ-1 do if not IsIntegral(sss[j][1]) then Append(~IndicesjWithsjNotIntegral,j); end if; end for; delta:=[RealField() | ]; for j:=1 to #JJJ-2 do delta[j]:=0; for i:=j+1 to #JJJ-1 do if delta[j] lt DistanceToNearestInteger(sss[i][1])*Norm(Transpose(BC)[i])^(1/2) then delta[j]:= DistanceToNearestInteger(sss[i][1])*Norm(Transpose(BC)[i])^(1/2); end if; end for; end for; delta[#JJJ-1]:=0; max:=0; for j in IndicesjWithsjNotIntegral do if max lt 2^(-(#JJJ-2)/2) * DistanceToNearestInteger(sss[j][1]) * Norm(Transpose(BC)[1])^(1/2) - (#JJJ - 1 - j)*delta[j] then max:=2^(-(#JJJ-2)/2) * DistanceToNearestInteger(sss[j][1]) * Norm(Transpose(BC)[1])^(1/2) - (#JJJ - 1 - j)*delta[j]; end if; end for; lowerbound:=max; /* 206  print("lowerbound, y ne 0:"); Floor(lowerbound); print("IndicesjWithsjNotIntegral"); IndicesjWithsjNotIntegral; */ /* print("DistanceToNearestInteger(sss[#JJJ-1][1]);"); RealField() ! DistanceToNearestInteger(sss[#JJJ-1][1]); print("DistanceToNearestInteger(sss[#JJJ-2][1]);"); RealField() ! DistanceToNearestInteger(sss[#JJJ-2][1]); */ /* print("Norm(Transpose(BC)[1]^(1/2))"); Norm(Transpose(BC)[1])^(1/2); print("2^(-(#JJJ-2)/2)"); 2^(-(#JJJ-2)/2); */ end if; //END IF /* print("(R^2 + S)^(1/2):"); Floor((R^2 + S)^(1/2)); */ /* print("lowerbound / (R^2 + S)^(1/2)"); lowerbound / (R^2 + S)^(1/2); */ if lowerbound gt (R^2 + S)^(1/2) then ////////// 207  /* Choose c11 to find an optimal i0-conditional upper bound for A from Lemma 19.2 */ ////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); max:=Max([ Floor((1/c11)*( Log(2*Log(2)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) )), Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; c11:=((1000000-1)/1000000)*c10/(n-1); max:=Max([ Floor((1/c11)*( Log(2*Log(2)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) )), Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); max:=Max([ Floor((1/c11)*( Log(2*Log(2)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) )), Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, 208  Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; end for; //end i loop ////  OldUnconditionalUpperBoundForA:=UpperBoundForA; NewConditionalUpperBoundForAi0:=MIN; if NewConditionalUpperBoundForAi0 lt OldUnconditionalUpperBoundForA then ConditionalUpperBoundForA[i0]:=NewConditionalUpperBoundForAi0; flag:=false; //ready to get out of while loop that increases C if //necessary else RunThroughNumber2:=RunThroughNumber2+1; //increase C and try again //////// /* In case we find a new conditional upper bound that fails to improve on the current unconditional upper bound for A, and this occurs 5 times wtih log(C) being increased 5% each time, then we abort the real reduction procedure.  There is no need to print a message in this case.  */ /////// if RunThroughNumber2 eq 5 then JumpToEndOfRealReduction:=true; break i0; end if; end if; /*controlled by NewConditionalUpperBoundForAi0 lt OldUnconditionalUpperBoundForA*/ else //controlled by lowerbound gt (R^2 + S)^(1/2)  209  RunThroughNumber1:=RunThroughNumber1+1; //increase C and try again ///// /* If increasing log(C) 22 times (with log(C) being increased 5% the first twenty times and by 1000% the last two times, so that log(C) will be 20 times original value) fails to produce a new conditional upper bound for A, then we abort the real reduction procedure.  Also, print  a message to the user indicating the basic real reduction procedure was unsuccesful for this reason.  Note: tries 21 and 22 only happen  if the upper for A has not been reduced much (or at all) from the linear forms in logs bound. */ //// if RunThroughNumber1 eq 23 then print("basic real reduction taking too long"); print("case"); iiii; print("i0"); i0; print("Improvement:"); Improvement; UpperBoundForn; UpperBoundForA; JumpToEndOfRealReduction:=true; /* GammaC:=Lattice(Transpose(AC)); w:=CoordinateSpace(GammaC) ! [0,yyy[2][1]]; ClosestVectorsMatrix(GammaC,w : Max:=5); */ break i0; end if; end if; //controlled by lowerbound gt (R^2 + S)^(1/2) 210  end while; /* This is the loop that increases log(C) if necessary. The while loop controlled by flag */ end for; //end i0 loop  if JumpToEndOfRealReduction eq false then ///////////// /* Choose c11 to find an optimal i0-conditional upper bound for A for i0 in {s+1,...,s+2t} from Lemma 19.1 */ /////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; 211  //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; c11:=((1000000 - 1)/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; 212  end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; end for;  //end i loop  ///// /* Compute the new unconditional bound for A */ ///// OldUpperBoundForA:=UpperBoundForA; NewUpperBoundForA:=Max([Max(ConditionalUpperBoundForA),MIN]); if NewUpperBoundForA lt OldUpperBoundForA then Improvement:=true; UpperBoundForA:=NewUpperBoundForA; for i:=1 to r do B[1+v+i]:=UpperBoundForA; end for; end if; end if; //controlled by JumpToEndOfRealReduction if UpperBoundForA lt 0 then //there are no solutions to the current case of (11) 213  continue iiii; end if;  ///////////////////////////////////////////////////////////////////////// /* Complex Case, i.e., s = 1,2 */ ///////////////////////////////////////////////////////////////////////// else //s=1,2 complex case B[2+v+r]:=Floor(2*Arcsin(1/4)/PI); for i in JJJ do B[2+v+r]:=B[2+v+r] + B[i]; end for;  JumpToEndOfRealReduction:=false; for i0:=1 to s do  ///////////////////////////////////////////////////////////////////////// /* Define weights W[i] (Section 19) R (Section 19) S (Section 19) CCCCCC = C (Section 19) Initialize: TC, where Transpose(TC) = U_C from Section 19 phi[i]:= phi_i from Section 19 */ ///////////////////////////////////////////////////////////////////////// 214  W:=[]; for i:=1 to 1+v+r do W[i]:=0; //initialize end for; H0prime:=0; for i:=2 to #JJJ do if H0prime lt B[JJJ[i]] then H0prime:=B[JJJ[i]]; end if; end for; W[1]:=0; for i:=2 to #JJJ do W[JJJ[i]]:=RoundP(H0prime/B[JJJ[i]]); end for; //print("weights"); //W; //print("B"); //B; R:=B[2+v+r]; for i in JJJ do R:=R + B[i]; end for; R:=(1/2)*R; //this is just an approximation to R S:=0; for i:=2 to #JJJ do S:=S+(W[JJJ[i]]^2)*(B[JJJ[i]]^2); end for; prod:=1; for i:=2 to #JJJ do prod:=prod*W[JJJ[i]]; end for; 215  /* LogC:= ((#JJJ)/2)*Log( (R^2 + S) / ( 2^(-(#JJJ)) * (Abs(LogarithmicAlphaC[i0][2+v+r])*prod)^(2/(#JJJ)) ) ); */ LogC:= ((#JJJ)/2)*Log( (R^2 + S) / ( 2^(-2*(#JJJ)) * (Abs(LogarithmicAlphaC[i0][2+v+r])*prod)^(2/(#JJJ)) ) );  //CCCCCC:=Ceiling(Exp(LogC)); TC:=ScalarMatrix(IntegerRing(),#JJJ,1); //#JJJ by #JJJ identity matrix phi:=[]; for i:=1 to 2+v+r do phi[i]:=0; end for; ///////////////////////////////////////////////////////////////////////// /* Start the while loop where C will be increased until a new conditional upper for A is found that improves on the uncondtional upper bound for A or until a number of increases of C have been made with no success. */ ///////////////////////////////////////////////////////////////////////// RunThroughNumber1:=0; RunThroughNumber2:=0; flag:=true; while flag do  216  ///////////////////////////////////////////////////////////////////////// /* Increase CCCCCC = C (if this is not the first attempt the basic real reduction procedure). Calculate the phi_i for i in JJJ. Calculate R. */ //////////////////////////////////////////////////////////////////////// CCCCCC:= Ceiling(Exp(LogC + ((RunThroughNumber1 + RunThroughNumber2)/20)*LogC)); if RunThroughNumber1 eq 21 and UpperBoundForA gt 100000 then CCCCCC:=Ceiling(Exp(LogC + 9*LogC)); end if; if RunThroughNumber1 eq 22 and UpperBoundForA gt 100000 then CCCCCC:=Ceiling(Exp(LogC + 19*LogC)); end if; if LogC/Log(10) gt (0.95)*realprecision then RealPrecisionMultiplier := RealPrecisionMultiplier + 1; continue PrecisionLoopVariable; end if; for i in JJJ do phi[i]:=Round(CCCCCC*LogarithmicAlphaC[i0][i]); end for; phi[2+v+r]:=Round(CCCCCC*LogarithmicAlphaC[i0][2+v+r]); /*This will never happen because LogarithmicAlphaC[i0][2+v+r] = Pi */ if Abs(phi[2+v+r]) lt 2 then if CCCCCC*LogarithmicAlphaC[i0][2+v+r] ge 0 then phi[2+v+r]:=2; else phi[2+v+r]:=-2; 217  end if; end if; if IsIntegral(phi[1]/phi[2+v+r]) then if Abs(phi[1]+1 - CCCCCC*LogarithmicAlphaC[i0][1]) le 1 then phi[1]:=phi[1]+1; else phi[1]:=phi[1]-1; end if; end if; R:=B[2+v+r]*Abs( CCCCCC*LogarithmicAlphaC[i0][2+v+r] -  phi[2+v+r] );  for i in JJJ do R:=R + B[i]*Abs( CCCCCC*LogarithmicAlphaC[i0][i] -  phi[i] );  end for; ///////////////////////////////////////////////////////////////////////// /* Compute: AC = A_C */ //////////////////////////////////////////////////////////////////////// AC:=ZeroMatrix(IntegerRing(),v+r+2,v+r+2); for i:=1 to 1+v+r do AC[i][i]:=W[i]; end for; for j:=1 to v+r+2 do AC[v+r+2][j]:=phi[j]; end for; for i:=1+v+r to 2 by -1 do if not i in JJJ then RemoveColumn(~AC,i); RemoveRow(~AC,i); 218  end if; end for; RemoveRow(~AC,1); RemoveColumn(~AC,1); //AC is now a #JJJ by #JJJ matrix AC:=AC*Transpose(TC); /* If this is the first run through Transpose(TC) is the identity. Otherwise Transpose(TC) is UC.  This will time in the LLL reduction. */  ///////////////////////////////////////////////////////////////////////// /* Compute LLL reduced basis for the lattice Gamma_C generated by columns of A_C.  The algoritm used is de Weger’s exact integer version of LLL.  Note: LLL(X) assumes ROWS of X span the lattice, so we need to feed it the transpose of A_C.  Similarly, it spits out the transpose of B_C and  the transpose of U_C */ ////////////////////////////////////////////////////////////////////////// //time temp,TC,rank:=LLL(Transpose(AC) : Proof:=true, Method:="Integral", Delta:=0.75, Eta:=0.5 ); BC:=MatrixRing(RationalField(),#JJJ) ! Transpose(temp); //columns are LLL-reduced basis for Gamma_C /* Here TC*Transpose(AC) = Transpose(BC). So with UC=Transpose(TC) we have AC*UC = BC, and With VC = BC*Transpose(TC)*BC^(-1) = AC*Transpose(TC)*AC^(-1), we have VC*AC = BC. 219  */ ////////////////////////////////////////////////////////////////////////// /* Compute the lower bound for l(Gamma_C,y).  If it is large enough (bigger  than sqrt(R^2 + S)), compute the new upper bound for n[L].  Otherwise,  increase C and reduce again (go back to the start of the while loop) */ ////////////////////////////////////////////////////////////////////////// //START IF if phi[1] eq 0 then //y = 0 case (vectors) //never happens by choice of //phi[1] // \vec{c}_1 = Transpose(BC)[1] lowerbound:= 2^(-(#JJJ-1)/2)*Norm( Transpose(BC)[1] )^(1/2); else  //y neq 0 case  yyy:=ZeroMatrix(RationalField(),#JJJ,1); yyy[#JJJ][1]:=-phi[1]; sss:=(BC^(-1))*yyy; IndicesjWithsjNotIntegral:=[]; for j:=1 to #JJJ do if not IsIntegral(sss[j][1]) then Append(~IndicesjWithsjNotIntegral,j); end if; end for; delta:=[RealField() | ]; for j:=1 to #JJJ-1 do delta[j]:=0; for i:=j+1 to #JJJ do if delta[j] lt 220  DistanceToNearestInteger(sss[i][1])*Norm(Transpose(BC)[i])^(1/2) then delta[j]:= DistanceToNearestInteger(sss[i][1])*Norm(Transpose(BC)[i])^(1/2); end if; end for; end for; delta[#JJJ]:=0; max:=0; for j in IndicesjWithsjNotIntegral do if max lt 2^(-(#JJJ-1)/2) * DistanceToNearestInteger(sss[j][1]) * Norm(Transpose(BC)[1])^(1/2) - (#JJJ - j)*delta[j] then max := 2^(-(#JJJ-1)/2) * DistanceToNearestInteger(sss[j][1]) * Norm(Transpose(BC)[1])^(1/2) - (#JJJ - j)*delta[j]; end if; end for; lowerbound:=max; end if; //END IF if lowerbound gt (R^2 + S)^(1/2) then ////////// /* Choose c11 to find an optimal i0-conditional upper bound for A from Lemma 19.2 */ ////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); max:=Max([ Floor((1/c11)*( Log(4*Arcsin(1/4)*c16[i0]) + Log(CCCCCC) 221  - Log((lowerbound^2 - S)^(1/2) - R) )), Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; c11:=((1000000-1)/1000000)*c10/(n-1); max:=Max([ Floor((1/c11)*( Log(4*Arcsin(1/4)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) )), Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); max:=Max([ Floor((1/c11)*( Log(4*Arcsin(1/4)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) )), Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; end for; //end i loop ////  OldUnconditionalUpperBoundForA:=UpperBoundForA; 222  NewConditionalUpperBoundForAi0:=MIN; if NewConditionalUpperBoundForAi0 lt OldUnconditionalUpperBoundForA then ConditionalUpperBoundForA[i0]:=NewConditionalUpperBoundForAi0; flag:=false; //ready to get out of while loop that increases C if //necessary else RunThroughNumber2:=RunThroughNumber2+1; //increase C and try again //////// /* In case we find a new conditional upper bound that fails to improve on the current unconditional upper bound for A, and this occurs 5 times wtih log(C) being increased 5% each time, then we abort the real reduction procedure.  There is no need to print a message in this case.  */ /////// if RunThroughNumber2 eq 5 then JumpToEndOfRealReduction:=true; break i0; end if; end if; /*controlled by NewConditionalUpperBoundForAi0 lt OldUnconditionalUpperBoundForA*/ else //controlled by lowerbound gt (R^2 + S)^(1/2) RunThroughNumber1:=RunThroughNumber1+1; //increase C and try again ///// /* If increasing log(C) 22 times (with log(C) being increased 5% the first twenty times and by 1000% the last two times, so that log(C) will be 20 times original value) fails to produce a new conditional upper bound for A, then we abort the real reduction procedure.  Also, print  a message to the user indicating the basic real reduction procedure was unsuccesful for this reason.  Note: tries 21 and 22 only happen  if the upper for A has not been reduced much (or at all) from the linear 223  forms in logs bound. */ //// if RunThroughNumber1 eq 23 then print("basic real reduction taking too long"); print("case"); iiii; print("i0"); i0; print("Improvement:"); Improvement; JumpToEndOfRealReduction:=true; break i0; end if; end if; //controlled by lowerbound gt (R^2 + S)^(1/2) end while; /* this is the loop that increases log(C) if necessary, the while loop controlled by flag */ end for; //end i0 loop  if JumpToEndOfRealReduction eq false then ///////////// /* Choose c11 to find an optimal i0-conditional upper bound for A for i0 in {s+1,...,s+2t} from Lemma 19.1 */ /////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); c15:=0; 224  if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; c11:=((1000000 - 1)/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then 225  max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; end for;  //end i loop  //MIN is now an i0-conditional upper bound for A for i0 in {s+1,...,s+2t} ///// /* Compute the new unconditional bound for A 226  */ ///// OldUpperBoundForA:=UpperBoundForA; NewUpperBoundForA:=Max([Max(ConditionalUpperBoundForA),MIN]); if NewUpperBoundForA lt OldUpperBoundForA then Improvement:=true; UpperBoundForA:=NewUpperBoundForA; for i:=1 to r do B[1+v+i]:=UpperBoundForA; end for; end if; end if; //controlled by JumpToEndOfRealReduction if UpperBoundForA lt 0 then //there are no solutions to the current case of (11) continue iiii; end if;  end if; //end of IF for distinguishing (s>=3) (s=1,2) cases end if; //end of IF for s=0, s>=3, s=1or2 cases //done finding new upper bound for A UpperBoundForH:=Max([UpperBoundForN, UpperBoundForA]); //print("at end of improvement loop:"); print("Upper bounds for the n_l and A, respectively:"); UpperBoundForn; 227  Floor(UpperBoundForA); end while;  //end loop for repeated simple reductions //(the improvement loop)  ///////////////////////////////////////////////////////////////////////// /* End Of Loop For Repeated Simple Reductions (the improvement loop) */ ///////////////////////////////////////////////////////////////////////// print("Starting refined reduction procedures."); /////////////////////////////////////////////////////////////////////// /* Initialize the set of exceptional tuples.  It will be filled as we work  through the refined redcution procedures. At the end, it will consist of the tuples that pass all the easy tests. The tuples will not have been tested for (11) directly and they won’t all necessarily be soltutions of (11).  We will test them more in the final  sieve step. Each element of ExceptionalTuples will be a sequence of the form [b_{JJJ[2]},...,b_{JJJ[#JJJ]}]. */ ///////////////////////////////////////////////////////////////////////// ExceptionalTuples:=[]; //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////// //////////////////////// /* Start Of Loop For Repeated Refined Reductions */ //////////////////////// 228  ////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// Improvement:=true; while Improvement do Improvement:=false;  ///////////////////////////////////////////////////////////////////////// /* If the number of tuples to sieve through is small enough, jump directly to the final sieving procedure. If the number of exceptional tuples has grown excessively large, jump to the final sieving procedure and inform that user that this has been done. */ ///////////////////////////////////////////////////////////////////////// prod:=1; for i in J do prod:=prod*(UpperBoundForn[i]+1); end for; prod:=prod*(2*UpperBoundForA + 1)^r; if prod lt 5000000 then print("The number of tuples to sieve is small. Jumping to the final sieving procedure."); break; end if; //prod = number of tuples to sieve if #ExceptionalTuples gt 100000 then print("The number of exceptional tuples is large. Jumping to the final sieving procedure."); print("Case:"); iiii; print("Upper bounds bor the n_i:"); UpperBoundForn; print("Upper bound for A:"); Floor(UpperBoundForA); break; end if; 229  ////////////////////////////////////////////////////////////////////////// /* Refined p_l-adic reduction for each l in I (Section 20) */ ////////////////////////////////////////////////////////////////////////// for l in I do  ////////////////////////////////////////////////////////////////////////// /* Define: W[i] = W_i (weights) for p_l (Section 20) QQ = Q (Section 20) mmmm = m for p_l (Section 20) Initialize: betam[i] = beta_i^(m) for p[L], Tm, where Transpose(Tm) = U_m from Section 20 */ ////////////////////////////////////////////////////////////////////////// W:=[]; for i:=1 to 1+v+r do W[i]:=0; //initialize end for; W[1]:=0; for i:=2 to #JJJ do W[JJJ[i]]:=RoundP(UpperBoundForH/B[JJJ[i]]); end for; for i in J do W[1+i]:=2*W[i+1]; end for; 230  //print("weights"); //W; //print("B"); //B; QQ:=0; for i in JJJ do QQ:=QQ+(W[i]^2)*(B[i]^2); //recall W[1]=0 end for; prod:=1; for i:=2 to #JJJ do prod:=prod*W[JJJ[i]]; end for; /* mmmm:=Ceiling( (3/4)*( (#JJJ - 1)/(2*Log(p[l])) )*Log( 2^(#JJJ - 1) * QQ / prod^(2/(#JJJ-1)) ) ); */ mmmm:=Min([ Ceiling( (3/4)*( (#JJJ - 1)/(2*Log(p[l])) )*Log( QQ / prod^(2/(#JJJ-1)) ) ), Ceiling((3/4)*UpperBoundForn[l]) ]);  betam:=[]; for i:=1 to 1+v+r do betam[i]:=0; end for;  231  Tm:=ScalarMatrix(IntegerRing(),#JJJ-1,1); /*initialize as #JJJ-1 by #JJJ-1 identity matrix*/ ///////////////////////////////////////////////////////////////////////// /* Start while loop that will increase m until the p_l-adic reduction yeilds a new upper bound for n_l or until a number of increases has been made with no success */ ///////////////////////////////////////////////////////////////////////// flag:=true; RunThroughNumber:=0; while flag do ///////////////////////////////////////////////////////////////////////// /* Increase mmmm = m (if this is not the first attempt with the basic p_l-reduction procedure). Calculuate betam[i] = beta_i^(m). */ //////////////////////////////////////////////////////////////////////// mmmm:=Ceiling( mmmm + (RunThroughNumber/20)*mmmm ); for i in JJJ do betam[i]:= SmallestNonnegativeRemainderModpLToThem(beta[l][i],l,mmmm); end for; //print("mmmm"); //mmmm; ////////////////////////////////////////////////////////////////////////// /* Compute the (soon to be) new upper bound for n_l.  If it is better than  the old upper bound, then we do the enumeration procedure.  If it is not  better, there is no need to do the enumeration and we move on to the next l in I */ 232  ///////////////////////////////////////////////////////////////////////// NewUpperBoundFornl:=Max([ Floor( (1/hh[l])*(1/(p[l]-1) - Valuation(delta2[l])) ), Ceiling((1/hh[l])*(mmmm-dd[l]))-1 ]); OldUpperBoundFornl:=UpperBoundForn[l]; if NewUpperBoundFornl ge OldUpperBoundFornl then continue l; else // NewUpperBoundFornl lt OldUpperBoundFornl  ////////////////////////////////////////////////////////////////////////// /* Define: Am = A_m for p[L] Gamma_m = lattice generated by columns of A_m */ ///////////////////////////////////////////////////////////////////////// Am:=ZeroMatrix(IntegerRing(), v+r+2, v+r+2); for i:=1 to v+r+1 do Am[i][i]:=W[i]; end for; for j:=1 to v+r+1 do Am[v+r+2][j]:=W[ihat[l]]*betam[j]; end for; Am[v+r+2][v+r+2]:=W[ihat[l]]*p[l]^mmmm; for i:=1+v+r to 2 by -1 do if i eq ihat[l] or not i in JJJ then RemoveColumn(~Am,i); RemoveRow(~Am,i); end if; 233  end for; RemoveColumn(~Am,1); RemoveRow(~Am,1); //Am is now a #JJJ-1 by #JJJ-1 matrix Am:=Am*Transpose(Tm); //Transpose(Tm) = Um from Setion 15 /* If this is the first run through, Tm is the identity. If this is not the first run through, this will save computation time. */ ///////////////////////////////////////////////////////////////////////// /* Compute an LLL reduced basis for the lattice Gamma_m generated by columns of A_m.  The algorithm used is de Weger’s exact integer version of LLL.  Note: LLL(X) assumes ROWS of X span the lattice, so we need to feed it the transpose of A_m.  Similarly, it spits out the transpose of B_m and  the transpose of U_m */ ///////////////////////////////////////////////////////////////////////// //time temp,Tm,rank:=LLL( Transpose(Am) : Proof:=true, Method:="Integral", Delta:=0.75, Eta:=0.5 ); Bm:=MatrixRing(RationalField(),#JJJ-1) ! Transpose(temp); //columns are LLL-reduced basis for Gamma_m /* Here Tm*Transpose(Am) = Transpose(Bm). So with Um=Transpose(Tm) we have Am*Um = Bm, and With Vm = Bm*Transpose(Tm)*Bm^(-1) = Am*Transpose(Tm)*Am^(-1), we have Vm*Am = Bm. 234  */ ///////////////////////////////////////////////////////////////////////// /* Define: yyy = \vec{y} from Section 20 sss = \vec{s} from Section 20 ttt = \vec{t} from Section 20 zzz = \vec{z} from Section 20 DDD = D from Section 20 */ ///////////////////////////////////////////////////////////////////////// yyy:=ZeroMatrix(RationalField(),2+v+r,1); for i:=1 to v do yyy[1+i][1]:=(1/2)*W[i+1]*B[i+1]; end for; for i:=1+v+r to 2 by -1 do if i eq ihat[l] or not i in JJJ then RemoveRow(~yyy,i); end if; end for; RemoveRow(~yyy,1); //yyy is now a #JJJ-1 by 1 column vector if ihat[l] le 1+v then yyy[#JJJ-1][1]:=-W[ihat[l]]*betam[1]+(1/2)*W[ihat[l]]*B[ihat[l]]; else //ihat[l] gt 1+v yyy[#JJJ-1][1]:=-W[ihat[l]]*betam[1]; end if; sss:=(Bm^(-1))*yyy; ttt:=sss; for i:=1 to #JJJ-1 do ttt[i][1]:=Floor(sss[i][1]); 235  end for; Floorsss:=ttt; potentialttt:=ttt; min:=LengthOfVector(Bm*ttt - yyy); mm:=#JJJ-1; Choosettt(~yyy,~ttt,~potentialttt,~Floorsss,~min,~Bm,~mm,1); zzz:=Bm*ttt; DDD:=0; for i in J do DDD:=DDD + ((1/2)*W[1+i]*B[1+i])^2; end for; for i:=1 to r do DDD:=DDD + (W[1+v+i]*B[1+v+i])^2; end for; DDD:=DDD^(1/2); DDD:=DDD+min;  //////////////////////////////////////////////////////////////////////// /* Construct the lattice Gamma_m.  The MAGMA function Lattice() assumes  Use the function EnumerationCost to compute an estimate the number of nodes in the tree to be visited during the execution of the algorithm that will enumerate all lattice vectors u with |u| \leq D.  The number  of nodes is essentially directly proportional to the time needed for the enumeration. If the number of nodes is too large for the enumration to be done in a reasonable amount of time, we increase m and try the reduction procedure again.  If several increases of m fail to result in a small enough  estimate for the number of nodes, then we move onto the next l in I. 236  In Stehle and Watkins (2006), it is asserted that MAGMA’s enumeration algorithm has a traversal rate of about 7.5 millon nodes per second. Based on the examples in the MAGMA Handbook, the rate is appears to be 20 to 40 millon nodes per second. We will assume a traversal rate of 10 millon nodes per second.  Assuming we want the enumeration to take less  than 10 minutes, we want to abort if the estimated number of nodes is > 10*60*10^7 = 6000000000 Note: To MAGMA, Norm(v) = |v|^2. */ //////////////////////////////////////////////////////////////////////// Gammam:=Lattice(Transpose(Bm));  if EnumerationCost(Gammam,RealField() ! DDD^2) gt 6000000000 then RunThroughNumber+:=1;  //increase m and try again  /// /* If increasing m 20 times (with m being increased by 5% each time, so that m will be double its original value after 20 increases) fails to result in a sufficiently small estimate for the number of nodes, then we move on to the next value of l in I.  Also, print a message indicating  that the refined p_l-adic reduction procedure was unsuccesful. */ ///// if RunThroughNumber eq 20 then print("Refined p-adic reduction taking too long."); print("Case:"); iiii; print("l:"); l; continue l; 237  end if; else // EnumerationCost(Gammam,UpperBoundForu^2) <= 6000000000 flag:=false; //ready to get out of while loop that increases m //if necessary //////////////////////////////////////////////////////////////////////// /* Create a process P to enumerate all the vectors u in the lattice Gamma_m with length squared |u|^2 <= D^2 (equivalently length |u| <= D). To enumerate the vectors, we will need to repeatedly call NextVector(P). Calling NextVector(P) will return the next vector found in the enumeration (along with its norm). IsEmpty(P) returns true if the process P has finished enumerating all the vectors.  It returns false otherwise.  */ //////////////////////////////////////////////////////////////////////// P:=ShortVectorsProcess(Gammam,Floor(DDD^2)); //////////////////////////////////////////////////////////////////////// /* Enumerate those lattice vectors u with ||u|| <= D, extract the corresponding tuples, and test those tuples. Extracted tuple = (b_{JJJ[2]},...,b_{JJJ[#JJJ]}) bbb[i] = b_{JJJ[i]}, i=1 to #JJJ Recall: For each ll in I, jl[ll] is the unique index such that JJJ[jl[ll]]=ll+1. So bbb[jl[ll]] = b_{ll+1} = n_ll */ //////////////////////////////////////////////////////////////////////// bbb:=[RationalField() | ]; 238  while not IsEmpty(P) do uuu:=NextVector(P); //Extract tuple (b_{JJJ[2]},...,b_{JJJ[#JJJ]}) bbb[1]:=1; if ihat[l] le 1+v then for i:=2 to istar[l]-1 do bbb[i]:=(uuu[i-1]-(yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; bbb[istar[l]]:=(uuu[#JJJ-1]-(yyy[#JJJ-1][1]-zzz[#JJJ-1][1]) + (1/2)*W[JJJ[istar[l]]]*B[JJJ[istar[l]]])/W[JJJ[istar[l]]]; for i:=istar[l]+1 to 1+#J do bbb[i]:=(uuu[i-2]-(yyy[i-2][1]-zzz[i-2][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; for i:=2+#J to #JJJ do bbb[i]:=(uuu[i-2]-(yyy[i-2][1]-zzz[i-2][1]))/W[JJJ[i]]; end for; else //ihat[l] gt 1+v for i:=2 to 1+#J do bbb[i]:=(uuu[i-1]-(yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; for i:=2+#J to istar[l]-1 do bbb[i]:=(uuu[i-1]-(yyy[i-1][1]-zzz[i-1][1]))/W[JJJ[i]]; end for; 239  bbb[istar[l]]:=(uuu[#JJJ-1]-(yyy[#JJJ-1][1]-zzz[#JJJ-1][1])) /W[JJJ[istar[l]]]; for i:=istar[l]+1 to #JJJ do bbb[i]:=(uuu[i-2]-(yyy[i-2][1]-zzz[i-2][1]))/W[JJJ[i]]; end for; end if; /* if bbb[1] ne 1 then print("something is wrong!"); bbb[1]; istar[l]; break iiii; end if; */ //test the tuple passes:=true; while true do //this while loop is a hack to provide a way to //"jump to line X" for i:=2 to #JJJ do if not IsIntegral(bbb[i]) then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2 to 1+#J do if bbb[i] gt B[JJJ[i]] or bbb[i] lt 0 then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2+#J to #JJJ do if bbb[i] gt B[JJJ[i]] or bbb[i] lt -B[JJJ[i]] then passes:=false; break; end if; end for; if passes eq false then break; end if; /*test if tuple fits in the new box.  If so, throw it away (it’s not 240  exceptional).  Recall bbb[jl[l]] = b_{l+1} = n_l*/  if bbb[jl[l]] le NewUpperBoundFornl then passes:=false; break; end if;  LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[l][JJJ[i]]; end for; if SpecialCase[l] eq true then if Valuation(LAMBDAprime) ne bbb[jl[l]]*hh[l] + dd[l] then passes:=false; break; end if; else //SpecialCase[l] eq false if Valuation(LAMBDAprime) lt bbb[jl[l]]*hh[l] + dd[l] then passes:=false; break; end if; end if;  for ll in I do if ll ne l then LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[ll][JJJ[i]]; end for; if SpecialCase[ll] eq true then if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) ne bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; else //SpecialCase[ll] eq false if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) lt bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; end if; 241  end if; end for; if passes eq false then break; end if;  if SpecialCase[l] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*LogarithmicAlphap[l][JJJ[i]]; end for; if Valuation(LAMBDA) ne bbb[jl[l]]*hh[l] + Valuation(delta2[l]) then passes:=false; break; end if; end if; //end IF controlled by SpecialCase[l]  for ll in I do if ll ne l then if SpecialCase[ll] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*beta[ll][JJJ[i]]; end for; if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDA) ne bbb[jl[ll]]*hh[ll] + Valuation(delta2[ll]) then passes:=false; break ll; end if; end if; //end IF controlled by SpecialCase[ll] end if; end for; if passes eq false then break; end if;  break; end while; //end hack while loop 242  //If the tuple passes all the tests, add it to the list of exceptional //tuples if passes eq true then Remove(~bbb,1); Include(~ExceptionalTuples, bbb); end if; //Since the enumeration process only spits out one of u and -u, we now //need to do the same thing with -u. uuu:=-uuu; //Extract tuple (b_{JJJ[2]},...,b_{JJJ[#JJJ]}) bbb[1]:=1; if ihat[l] le 1+v then for i:=2 to istar[l]-1 do bbb[i]:=(uuu[i-1]-(yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; bbb[istar[l]]:=(uuu[#JJJ-1]-(yyy[#JJJ-1][1]-zzz[#JJJ-1][1]) + (1/2)*W[JJJ[istar[l]]]*B[JJJ[istar[l]]])/W[JJJ[istar[l]]]; for i:=istar[l]+1 to 1+#J do bbb[i]:=(uuu[i-2]-(yyy[i-2][1]-zzz[i-2][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]]) /W[JJJ[i]]; end for; for i:=2+#J to #JJJ do bbb[i]:=(uuu[i-2]-(yyy[i-2][1]-zzz[i-2][1]))/W[JJJ[i]]; end for; else //ihat[l] gt 1+v for i:=2 to 1+#J do bbb[i]:=(uuu[i-1]-(yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; 243  end for; for i:=2+#J to istar[l]-1 do bbb[i]:=(uuu[i-1]-(yyy[i-1][1]-zzz[i-1][1]))/W[JJJ[i]]; end for; bbb[istar[l]]:=(uuu[#JJJ-1]-(yyy[#JJJ-1][1]-zzz[#JJJ-1][1])) /W[JJJ[istar[l]]]; for i:=istar[l]+1 to #JJJ do bbb[i]:=(uuu[i-2]-(yyy[i-2][1]-zzz[i-2][1]))/W[JJJ[i]]; end for; end if; /* if bbb[1] ne 1 then print("something is wrong!"); end if; */ //test the tuple passes:=true; while true do //this while loop is a hack to provide a way to //"jump to line X" for i:=2 to #JJJ do if not IsIntegral(bbb[i]) then passes:=false; break; end if; end for; if passes eq false then break; end if;  for i:=2 to 1+#J do if bbb[i] gt B[JJJ[i]] or bbb[i] lt 0 then passes:=false; break; end if; end for; if passes eq false then break; end if;  for i:=2+#J to #JJJ do if bbb[i] gt B[JJJ[i]] or bbb[i] lt -B[JJJ[i]] then 244  passes:=false; break; end if; end for; if passes eq false then break; end if;  /*test if tuple fits in the new box. exceptional).  If so, throw it away (it’s not  Recall bbb[jl[l]] = b_{l+1} = n_l*/  if bbb[jl[l]] le NewUpperBoundFornl then passes:=false; break; end if;  LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[l][JJJ[i]]; end for;  if SpecialCase[l] eq true then if Valuation(LAMBDAprime) ne bbb[jl[l]]*hh[l] + dd[l] then passes:=false; break; end if; else //SpecialCase[l] eq false if Valuation(LAMBDAprime) lt bbb[jl[l]]*hh[l] + dd[l] then passes:=false; break; end if; end if;  for ll in I do if ll ne l then LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[ll][JJJ[i]]; end for; if SpecialCase[ll] eq true then if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) ne bbb[jl[ll]]*hh[ll] + dd[ll] then 245  passes:=false; break ll; end if; else //SpecialCase[ll] eq false if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) lt bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; end if; end if; end for; if passes eq false then break; end if;  if SpecialCase[l] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*LogarithmicAlphap[l][JJJ[i]]; end for; if Valuation(LAMBDA) ne bbb[jl[l]]*hh[l] + Valuation(delta2[l]) then passes:=false; break; end if; end if; //end IF controlled by SpecialCase[l]  for ll in I do if ll ne l then if SpecialCase[ll] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*beta[ll][JJJ[i]]; end for; if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDA) ne bbb[jl[ll]]*hh[ll] + Valuation(delta2[ll]) then passes:=false; break ll; end if; 246  end if; //end IF controlled by SpecialCase[ll] end if; end for; if passes eq false then break; end if; break; end while; //end hack while loop //If the tuple passes all the tests, add it to the list of exceptional //tuples if passes eq true then Remove(~bbb,1); Include(~ExceptionalTuples, bbb); end if;  end while; //enumeration loop //Enumeration done  Improvement:=true; UpperBoundForn[l]:=NewUpperBoundFornl; B[1+l]:=UpperBoundForn[l]; end if; // end of IF controlled by EnumerationCost(Gammam,D^2)  end if; // end of IF controlled by NewUpperBoundFornl ge // OldUpperBoundFornl  end while; //this is the loop that increases m if needed end for; // end l loop UpperBoundForN:=Max(UpperBoundForn); 247  ///////////////////////////////////////////////////////////////////////// /* Refined Real Reduction (Section 21) */ ///////////////////////////////////////////////////////////////////////// for i0:=1 to s do ConditionalUpperBoundForA[i0]:=UpperBoundForA; end for; ///////////////////////////////////////////////////////////////////////// /* Totally Complex Case, i.e, s=0 */ //////////////////////////////////////////////////////////////////////// if s eq 0 then //Choose c11 to find an choose optimal upper bound for A from Lemma 19.1 MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); c15:=0; min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt 248  Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; c11:=((1000000 - 1)/1000000)*c10/(n-1); c15:=0; min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); c15:=0; min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); 249  end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; end for;  //end i loop  OldUpperBoundForA:=UpperBoundForA; NewUpperBoundForA:=MIN; if NewUpperBoundForA lt OldUpperBoundForA then Improvement:=true; UpperBoundForA:=NewUpperBoundForA; end if; else //s > 0 ///////////////////////////////////////////////////////////////////////// /* s>0 Case */ ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// /* Real Case, i.e., s \geq 3 */ ///////////////////////////////////////////////////////////////////////// if s ge 3 then // s>=3 real case  250  JumpToEndOfRealReduction:=false; for i0:=1 to s do //print("refined real, i0="); //i0; ///////////////////////////////////////////////////////////////////////// /* Define weights W[i] (Section 21) R (approximation) (Section 21) S (Section 21) CCCCCC = C (Section 21) Initialize: TC, where Transpose(TC) = U_C from Section 21 phi[i]:= phi_i from Section 21 */ ///////////////////////////////////////////////////////////////////////// W:=[]; for i:=1 to 1+v+r do W[i]:=0; //initialize end for; H0prime:=0; for i:=2 to #JJJ-1 do if H0prime lt B[JJJ[i]] then H0prime:=B[JJJ[i]]; end if; end for; W[1]:=0; for i:=2 to #JJJ-1 do W[JJJ[i]]:=RoundP(H0prime/B[JJJ[i]]); end for; for i in J do W[1+i]:=2*W[i+1]; 251  end for; //print("weights"); //W; //print("B"); //B; R:=0; for i in JJJ do R:=R + B[i]; end for; R:=(1/2)*R; //this is just an approximation to R S:=0; for i:=2 to #JJJ-1 do S:=S+(W[JJJ[i]]^2)*(B[JJJ[i]]^2); end for; prod:=1; for i:=2 to #JJJ-1 do prod:=prod*W[JJJ[i]]; end for; /* LogC:= (3/4) * ((#JJJ-1)/2) * Log( (R^2 + S) / ( 2^(-(#JJJ-1)) * (Abs(LogarithmicAlphaC[i0][JJJ[#JJJ]])*prod)^(2/(#JJJ-1)) ) ); */ LogC:= Min([ (3/4) * ((#JJJ-1)/2) * Log( (R^2 + S) / (  (Abs(LogarithmicAlphaC[i0][JJJ[#JJJ]])*prod)^(2/(#JJJ-1)) )  ), 252  (3/4)*UpperBoundForA ]); //CCCCCC:=Ceiling(Exp(LogC)); TC:=ScalarMatrix(IntegerRing(),#JJJ-1,1); //#JJJ-1 by #JJJ-1 identity matrix phi:=[]; for i:=1 to 1+v+r do phi[i]:=0; end for; ///////////////////////////////////////////////////////////////////////// /* Start the while loop where C will be increased until we find a new conditional upper for A that is smaller than the uncondtional upper bound for A or until a number of increases of C have been made with no success. */ //////////////////////////////////////////////////////////////////////// RunThroughNumber1:=0; RunThroughNumber2:=0; flag:=true; while flag do  ///////////////////////////////////////////////////////////////////////// /* Increase CCCCCC = C (if this is not the first attempt the basic real reduction procedure). */ ///////////////////////////////////////////////////////////////////////// CCCCCC:= 253  Ceiling(Exp(LogC + ((RunThroughNumber1 + RunThroughNumber2)/20)*LogC)); //print("CCCCCC"); //CCCCCC; ///////////////////////////////////////////////////////////////////////// /* Compute the (soon to be) new i0-conditional upper bound for A. We choose c11 to optimize this bound. If it is better than the old unconditional upper bound, then we do the enumeration procedure.  If it is not better, then we first retry several  times with larger values of C, but if that doesn’t work we abandon the refined real reduction procedure (there is no point in moving on to the next i0 in {1,...,s} because the uncondtional upper bound on A will not be improved). */ ///////////////////////////////////////////////////////////////////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); max:=Max([ Ceiling((1/c11)*( Log(2*Log(2)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) ))-1, Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; c11:=((1000000-1)/1000000)*c10/(n-1); max:=Max([ Ceiling((1/c11)*( Log(2*Log(2)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) ))-1, Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, 254  Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); max:=Max([ Ceiling((1/c11)*( Log(2*Log(2)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) ))-1, Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; end for; //end i loop NewConditionalUpperBoundForAi0:=MIN; OldUnconditionalUpperBoundForA:=UpperBoundForA; if NewConditionalUpperBoundForAi0 ge OldUnconditionalUpperBoundForA then RunThroughNumber2:=RunThroughNumber2+1; //increase C and try again //////// /* In case we find a new conditional upper bound that fails to improve on the current unconditional upper bound for A, and this occurs 5 times with log(C) being increased 5% each time, then we abort the real reduction procedure.  There is no need to print a message in this case.  */ /////// if RunThroughNumber2 eq 5 then JumpToEndOfRealReduction:=true; print("RunThroughNumber2 = "); 255  RunThroughNumber2; break i0; end if; else //NewConditionalUpperBoundForAi0 lt OldUnconditionalUpperBoundForA ////////////////////////////////////////////////////////////////////////// /* Calculate the phi_i for i in JJJ. Calculate R. */ ////////////////////////////////////////////////////////////////////////// for i in JJJ do phi[i]:=Round(CCCCCC*LogarithmicAlphaC[i0][i]); end for; if Abs(phi[JJJ[#JJJ]]) lt 2 then if CCCCCC*LogarithmicAlphaC[i0][JJJ[#JJJ]] ge 0 then phi[JJJ[#JJJ]]:=2; else phi[JJJ[#JJJ]]:=-2; end if; end if; if IsIntegral(phi[1]/phi[JJJ[#JJJ]]) then if Abs(phi[1]+1 - CCCCCC*LogarithmicAlphaC[i0][1]) le 1 then phi[1]:=phi[1]+1; else phi[1]:=phi[1]-1; end if; end if; R:=0; for i in JJJ do 256  R:=R + B[i]*Abs( CCCCCC*LogarithmicAlphaC[i0][i] -  phi[i] );  end for; ///////////////////////////////////////////////////////////////////////// /* Compute AC = A_C */ ///////////////////////////////////////////////////////////////////////// AC:=ZeroMatrix(IntegerRing(),v+r+1,v+r+1); for i:=1 to v+r do AC[i][i]:=W[i]; end for; for j:=1 to v+r+1 do AC[v+r+1][j]:=phi[j]; end for; for i:=1+v+r to 2 by -1 do if not i in JJJ then RemoveColumn(~AC,i); RemoveRow(~AC,i); end if; end for; RemoveRow(~AC,1); RemoveColumn(~AC,1); //AC is now a #JJJ-1 by #JJJ-1 matrix AC:=AC*Transpose(TC); /* If this is the first run through Transpose(TC) is the identity. Otherwise Transpose(TC) is UC.  This will save time in the LLL  reduction. */  257  //////////////////////////////////////////////////////////////////////// /* Compute an LLL reduced basis for the lattice Gamma_C generated by columns of A_C.  The algoritm used is de Weger’s exact integer version of LLL.  Note: LLL(X) assumes ROWS of X span the lattice, so we need to feed it the transpose of A_C.  Similarly, it spits out the transpose of B_C and  the transpose of U_C */ ///////////////////////////////////////////////////////////////////////// //time temp,TC,rank:=LLL(Transpose(AC) : Proof:=true, Method:="Integral", Delta:=0.75, Eta:=0.5 ); BC:=MatrixRing(RationalField(),#JJJ-1) ! Transpose(temp); //columns are LLL-reduced basis for Gamma_C /* Here TC*Transpose(AC) = Transpose(BC). So with UC=Transpose(TC) we have AC*UC = BC, and With VC = BC*Transpose(TC)*BC^(-1) = AC*Transpose(TC)*AC^(-1), we have VC*AC = BC. */ ///////////////////////////////////////////////////////////////////////// /* Define: yyy = \vec{y} from Section 21 sss = \vec{s} from Section 21 ttt = \vec{t} from Section 21 zzz = \vec{z} from Section 21 DDD = D from Section 21 */ ///////////////////////////////////////////////////////////////////////// 258  yyy:=ZeroMatrix(RationalField(),1+v+r,1); for i:=1 to v do yyy[1+i][1]:=(1/2)*W[1+i]*B[1+i]; end for; for i:=1+v+r to 2 by -1 do if not i in JJJ then RemoveRow(~yyy,i); end if; end for; RemoveRow(~yyy,1); //yyy is now a #JJJ-1 by 1 column vector yyy[#JJJ-1][1]:=-phi[1]; sss:=(BC^(-1))*yyy; ttt:=sss; for i:=1 to #JJJ-1 do ttt[i][1]:=Floor(sss[i][1]); end for; Floorsss:=ttt; potentialttt:=ttt; min:=LengthOfVector(BC*ttt - yyy); mm:=#JJJ-1; Choosettt(~yyy,~ttt,~potentialttt,~Floorsss,~min,~BC,~mm,1); zzz:=BC*ttt; /*Now zzz is likely the closest vector in the lattice Gamma_C to yyy and min = |zzz-yyy|*/ DDD:=((R+1)^2 + S)^(1/2); //////////////////////////////////////////////////////////////////////// /* 259  Construct the lattice Gamma_C.  The MAGMA function Lattice() assumes  Use the function EnumerationCost to compute an estimate the number of nodes in the tree to be visited during the execution of the algorithm that will enumerate all lattice vectors u with |u| \leq D + |y-z|.  The  number of nodes is essentially directly proportional to the time needed for the enumeration. If the number of nodes is too large for the enumration to be done in a reasonable amount of time, we increase C and try the reduction procedure again.  If several increases of C fail to result in a small enough  estimate for the number of nodes, then we abort the refined real reduction (there is no point in moving on to the next i0 in {1,...,s} because the uncondtional upper bound on A will not be improved). In Stehle and Watkins (2006), it is asserted that MAGMA’s enumeration algorithm has a traversal rate of about 7.5 millon nodes per second. Based on the examples in the MAGMA Handbook, the rate is appears to be 20 to 40 millon nodes per second. We will assume a traversal rate of 10 millon nodes per second.  Assuming we want the enumeration to take less  than 10 minutes, we want to abort if the estimated number of nodes is > 10*60*10^7 = 6000000000 Note: To MAGMA, Norm(v) = |v|^2. */ //////////////////////////////////////////////////////////////////////// GammaC:=Lattice(Transpose(BC)); if EnumerationCost(GammaC,RealField() ! (DDD+min)^2) gt 6000000000 then RunThroughNumber1+:=1;  //increase C and try again  ///// /* If increasing log(C) 20 times (with log(C) being increased 5% each time, 260  so that log(C) will be double its original value) fails to produce a new conditional upper bound for A, then we abort the real reduction procedure. Also, print a message to the user indicating the refined real reduction procedure was unsuccesful for this reason. */ //// if RunThroughNumber1 eq 20 then print("Refined real reduction taking too long."); print("Case:"); iiii; print("i0:"); i0; JumpToEndOfRealReduction:=true; break i0; end if; else // EnumerationCost(GammaC,(DDD+min)^2) <= 6000000000 flag:=false; //ready to get out of while loop that increases C //if necessary //////////////////////////////////////////////////////////////////////// /* Create a process P to enumerate all the vectors u in the lattice Gamma_C with lenght squared |u|^2 <= (D+|y-z|)^2 (equivalently length |u| <= D+|y-z|). To enumerate the vectors, we will need to repeatedly call NextVector(P). Callign NextVector(P) will return the next vector found in the enumeration (along with its norm). IsEmpty(P) returns true if the process P has finished enumerating all the vectors.  It returns false otherwise.  */ ////////////////////////////////////////////////////////////////////////// P:=ShortVectorsProcess(GammaC,Floor((DDD+min)^2));  261  ///////////////////////////////////////////////////////////////////////// /* Enumerate those lattice vectors u with |u| <= D+|y-z|, extract the corresponding tuples, and test those tuples. Extracted tuple = (b_{JJJ[2]},...,b_{JJJ[#JJJ]}) bbb[i] = b_{JJJ[i]}, i=1 to #JJJ */ //////////////////////////////////////////////////////////////////////// bbb:=[RationalField() | ];  while not IsEmpty(P) do uuu:=NextVector(P); //Extract tuple (b_{JJJ[2]},...,b_{JJJ[#JJJ]}) bbb[1]:=1; for i:=2 to 1+#J do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; for i:=2+#J to #JJJ-1 do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]))/W[JJJ[i]]; end for; sum:=0; for i:=1 to #JJJ-1 do sum:=sum+bbb[i]*phi[JJJ[i]]; end for; bbb[#JJJ] := (uuu[#JJJ-1] - (yyy[#JJJ-1][1]-zzz[#JJJ-1][1]) - sum) /phi[JJJ[#JJJ]];  262  //Test the tuple passes:=true; while true do //this while loop is a hack to provide a way to //"jump to line X" for i:=2 to #JJJ do if not IsIntegral(bbb[i]) then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2 to 1+#J do if bbb[i] gt B[JJJ[i]] or bbb[i] lt 0 then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2+#J to #JJJ do if bbb[i] gt B[JJJ[i]] or bbb[i] lt -B[JJJ[i]] then passes:=false; break; end if; end for; if passes eq false then break; end if; /*Test if the tuple fits in the new box.  If so, throw it away (it’s not  exceptional). */ FitsInTheNewBox:=true; for i:=2+#J to #JJJ do if Abs(bbb[i]) gt NewConditionalUpperBoundForAi0 then FitsInTheNewBox:=false; break i; end if; end for; if FitsInTheNewBox eq true then passes:=false; break; end if; for ll in I do LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[ll][JJJ[i]]; 263  end for; if SpecialCase[ll] eq true then if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) ne bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; else //SpecialCase[ll] eq false if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) lt bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if; for ll in I do if SpecialCase[ll] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*beta[ll][JJJ[i]]; end for; if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDA) ne bbb[jl[ll]]*hh[ll] + Valuation(delta2[ll]) then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if;  break; end while; //end hack while loop /*If the tuple passes all the tests, add it to the list of exceptional tuples*/ 264  if passes eq true then Remove(~bbb,1); Include(~ExceptionalTuples, bbb); end if; // /*Since the enumeration process only spits out one of u and -u, we now need to do the same thing with -u.*/ uuu:=-uuu; //Extract tuple (b_{JJJ[2]},...,b_{JJJ[#JJJ]}) bbb[1]:=1; for i:=2 to 1+#J do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; for i:=2+#J to #JJJ-1 do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]))/W[JJJ[i]]; end for; sum:=0; for i:=1 to #JJJ-1 do sum:=sum+bbb[i]*phi[JJJ[i]]; end for; bbb[#JJJ] := (uuu[#JJJ-1] - (yyy[#JJJ-1][1]-zzz[#JJJ-1][1]) - sum) /phi[JJJ[#JJJ]]; //Test the tuple passes:=true; while true do //this while loop is a hack to provide a way to //"jump to line X" for i:=2 to #JJJ do if not IsIntegral(bbb[i]) then passes:=false; break; end if; end for; 265  if passes eq false then break; end if; for i:=2 to 1+#J do if bbb[i] gt B[JJJ[i]] or bbb[i] lt 0 then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2+#J to #JJJ do if bbb[i] gt B[JJJ[i]] or bbb[i] lt -B[JJJ[i]] then passes:=false; break; end if; end for; if passes eq false then break; end if; /*Test if the tuple fits in the new box.  If so, throw it away (it’s not  exceptional). */ FitsInTheNewBox:=true; for i:=2+#J to #JJJ do if Abs(bbb[i]) gt NewConditionalUpperBoundForAi0 then FitsInTheNewBox:=false; break i; end if; end for; if FitsInTheNewBox eq true then passes:=false; break; end if; for ll in I do LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[ll][JJJ[i]]; end for; if SpecialCase[ll] eq true then if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) ne bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; else //SpecialCase[ll] eq false if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) 266  and Valuation(LAMBDAprime) lt bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if; for ll in I do if SpecialCase[ll] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*beta[ll][JJJ[i]]; end for; if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDA) ne bbb[jl[ll]]*hh[ll] + Valuation(delta2[ll]) then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if;  break; end while; //end hack while loop /*If the tuple passes all the tests, add it to the list of exceptional tuples*/ if passes eq true then Remove(~bbb,1); Include(~ExceptionalTuples, bbb); end if;  end while; //enumeration loop //Enumeration done  267  ConditionalUpperBoundForA[i0]:=NewConditionalUpperBoundForAi0;  end if; //end of IF controlled by EnumerationCost(GammaC,(DDD+min)^2) end if; /* end of IF controlled by NewConditionalUpperBoundForAi0 ge OldUnconditionalUpperBoundForA */ end while; /* this is the while loop that increases log(C) if necessary, the while loop controlled by flag */  end for; //end i0 loop  if JumpToEndOfRealReduction eq false then ///////////// /* Choose c11 to find an optimal i0-conditional upper bound for A for i0 in {s+1,...,s+2t} from Lemma 19.1 */ /////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; 268  end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; c11:=((1000000 - 1)/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); 269  c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; end for;  //end i loop  ///// /* Compute the new unconditional bound for A */ /////  OldUpperBoundForA:=UpperBoundForA; NewUpperBoundForA:=Max([Max(ConditionalUpperBoundForA),MIN]);  if NewUpperBoundForA lt OldUpperBoundForA then Improvement:=true; 270  UpperBoundForA:=NewUpperBoundForA; for i:=1 to r do B[1+v+i]:=UpperBoundForA; end for; end if; end if; //controlled by JumpToEndOfRealReduction if UpperBoundForA lt 0 then //there are no solutions to the current case of (11) continue iiii; end if;  ///////////////////////////////////////////////////////////////////////// /* Complex Case, i.e., s = 1,2 */ ///////////////////////////////////////////////////////////////////////// else //s=1,2 complex case B[2+v+r]:=Floor(2*Arcsin(1/4)/PI); for i in JJJ do B[2+v+r]:=B[2+v+r] + B[i]; end for;  JumpToEndOfRealReduction:=false; for i0:=1 to s do  ///////////////////////////////////////////////////////////////////////// 271  /* Define weights W[i] (Section 21) R (approximation) (Section 21) S (Section 21) CCCCCC = C (Section 21) Initialize: TC, where Transpose(TC) = U_C from Section 21 phi[i]:= phi_i from Section 21 */ ///////////////////////////////////////////////////////////////////////// W:=[]; for i:=1 to 1+v+r do W[i]:=0; //initialize end for; H0prime:=0; for i:=2 to #JJJ do if H0prime lt B[JJJ[i]] then H0prime:=B[JJJ[i]]; end if; end for; W[1]:=0; for i:=2 to #JJJ do W[JJJ[i]]:=RoundP(H0prime/B[JJJ[i]]); end for; for i in J do W[1+i]:=2*W[i+1]; end for; R:=B[2+v+r]; for i in JJJ do R:=R + B[i]; end for; R:=(1/2)*R; 272  //this is just an approximation to R S:=0; for i:=2 to #JJJ do S:=S+(W[JJJ[i]]^2)*(B[JJJ[i]]^2); end for; prod:=1; for i:=2 to #JJJ do prod:=prod*W[JJJ[i]]; end for; /* LogC:= (3/4) * ((#JJJ)/2) * Log( (R^2 + S) / ( 2^(-(#JJJ)) * (Abs(LogarithmicAlphaC[i0][2+v+r])*prod)^(2/(#JJJ)) ) ); */ LogC:= Min([ (3/4) * ((#JJJ)/2) * Log( (R^2 + S) / ( (Abs(LogarithmicAlphaC[i0][2+v+r])*prod)^(2/(#JJJ)) ) ), (3/4)*UpperBoundForA ]); //CCCCCC:=Ceiling(Exp(LogC)); TC:=ScalarMatrix(IntegerRing(),#JJJ,1); //#JJJ by #JJJ identity matrix phi:=[]; for i:=1 to 2+v+r do phi[i]:=0; end for;  273  ////////////////////////////////////////////////////////////////////////// /* Start the while loop where C will be increased until we find a new conditional upper for A that is smaller than the uncondtional upper bound for A or until a number of increases of C have been made with no success. */ ////////////////////////////////////////////////////////////////////////// RunThroughNumber1:=0; RunThroughNumber2:=0; flag:=true; while flag do ////////////////////////////////////////////////////////////////////////// /* Increase CCCCCC = C (if this is not the first attempt the basic real reduction procedure). */ ////////////////////////////////////////////////////////////////////////// CCCCCC:= Ceiling(Exp(LogC + ((RunThroughNumber1 + RunThroughNumber2)/20)*LogC)); ///////////////////////////////////////////////////////////////////////// /* Compute the (soon to be) new i0-conditional upper bound for A. We choose c11 to optimize this bound. If it is better than the old unconditional upper bound, then we do the enumeration procedure.  If it is not better, then we first retry several  times with larger values of C, but if that doesn’t work we abandon the refined real reduction procedure (there is no point in moving on to the next i0 in {1,...,s} because the uncondtional upper bound on A will not be improved). */ ///////////////////////////////////////////////////////////////////////// 274  MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); max:=Max([ Ceiling((1/c11)*( Log(4*Arcsin(1/4)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) ))-1, Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; c11:=((1000000-1)/1000000)*c10/(n-1); max:=Max([ Ceiling((1/c11)*( Log(4*Arcsin(1/4)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) ))-1, Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); max:=Max([ Ceiling((1/c11)*( Log(4*Arcsin(1/4)*c16[i0]) + Log(CCCCCC) - Log((lowerbound^2 - S)^(1/2) - R) ))-1, Ceiling((c8prime + c9prime*UpperBoundForN)/(c10 - (n-1)*c11))-1, Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10 - c11))-1, Ceiling(Log(2*c16[i0])/c11)-1, 0 ]); if max lt MIN then MIN:=max; end if; 275  end for; //end i loop NewConditionalUpperBoundForAi0:=MIN; OldUnconditionalUpperBoundForA:=UpperBoundForA; if NewConditionalUpperBoundForAi0 ge OldUnconditionalUpperBoundForA then RunThroughNumber2:=RunThroughNumber2+1; //increase C and try again //////// /* In case we find a new conditional upper bound that fails to improve on the current unconditional upper bound for A, and this occurs 5 times with log(C) being increased 5% each time, then we abort the real reduction procedure.  There is no need to print a message in this case.  */ /////// if RunThroughNumber2 eq 5 then JumpToEndOfRealReduction:=true; break i0; end if; else //NewConditionalUpperBoundForAi0 lt OldUnconditionalUpperBoundForA ///////////////////////////////////////////////////////////////////////// /* Calculate the phi_i for i in JJJ. Calculate R. */ ////////////////////////////////////////////////////////////////////////// for i in JJJ do phi[i]:=Round(CCCCCC*LogarithmicAlphaC[i0][i]); end for; phi[2+v+r]:=Round(CCCCCC*LogarithmicAlphaC[i0][2+v+r]); /*This will never happen because LogarithmicAlphaC[i0][2+v+r] = Pi */ 276  if Abs(phi[2+v+r]) lt 2 then if CCCCCC*LogarithmicAlphaC[i0][2+v+r] ge 0 then phi[#JJJ]:=2; else phi[#JJJ]:=-2; end if; end if; if IsIntegral(phi[1]/phi[2+v+r]) then if Abs(phi[1]+1 - CCCCCC*LogarithmicAlphaC[i0][1]) le 1 then phi[1]:=phi[1]+1; else phi[1]:=phi[1]-1; end if; end if; R:=B[2+v+r]*Abs( CCCCCC*LogarithmicAlphaC[i0][2+v+r] -  phi[2+v+r] );  for i in JJJ do R:=R + B[i]*Abs( CCCCCC*LogarithmicAlphaC[i0][i] -  phi[i] );  end for; ///////////////////////////////////////////////////////////////////////// /* Compute AC = A_C */ ////////////////////////////////////////////////////////////////////////// AC:=ZeroMatrix(IntegerRing(),v+r+2,v+r+2); for i:=1 to 1+v+r do AC[i][i]:=W[i]; end for; for j:=1 to v+r+2 do AC[v+r+2][j]:=phi[j]; end for; 277  for i:=1+v+r to 2 by -1 do if not i in JJJ then RemoveColumn(~AC,i); RemoveRow(~AC,i); end if; end for; RemoveRow(~AC,1); RemoveColumn(~AC,1); //AC is now a #JJJ by #JJJ matrix AC:=AC*Transpose(TC); /* If this is the first run through Transpose(TC) is the identity. Otherwise Transpose(TC) is UC.  This will time in the LLL reduction. */  ////////////////////////////////////////////////////////////////////////// /* Compute an LLL reduced basis for the lattice Gamma_C generated by columns of A_C.  The algoritm used is de Weger’s exact integer version of LLL.  Note: LLL(X) assumes ROWS of X span the lattice, so we need to feed it the transpose of A_C.  Similarly, it spits out the transpose of B_C and  the transpose of U_C */ ///////////////////////////////////////////////////////////////////////// //time temp,TC,rank:=LLL(Transpose(AC) : Proof:=true, Method:="Integral", Delta:=0.75, Eta:=0.5 ); BC:=MatrixRing(RationalField(),#JJJ) ! Transpose(temp); //columns are LLL-reduced basis for Gamma_C /* 278  Here TC*Transpose(AC) = Transpose(BC). So with UC=Transpose(TC) we have AC*UC = BC, and With VC = BC*Transpose(TC)*BC^(-1) = AC*Transpose(TC)*AC^(-1), we have VC*AC = BC. */ ///////////////////////////////////////////////////////////////////////// /* Define: yyy = \vec{y} from Section 21 sss = \vec{s} from Section 21 ttt = \vec{t} from Section 21 zzz = \vec{z} from Section 21 DDD = D from Section 21 */ ///////////////////////////////////////////////////////////////////////// yyy:=ZeroMatrix(RationalField(),2+v+r,1); for i:=1 to v do yyy[1+i][1]:=(1/2)*W[1+i]*B[1+i]; end for; for i:=1+v+r to 2 by -1 do if not i in JJJ then RemoveRow(~yyy,i); end if; end for; RemoveRow(~yyy,1); //yyy is now a #JJJ by 1 column vector yyy[#JJJ][1]:=-phi[1]; sss:=(BC^(-1))*yyy; ttt:=sss; for i:=1 to #JJJ do ttt[i][1]:=Floor(sss[i][1]); 279  end for; Floorsss:=ttt; potentialttt:=ttt; min:=LengthOfVector(BC*ttt - yyy); mm:=#JJJ; Choosettt(~yyy,~ttt,~potentialttt,~Floorsss,~min,~BC,~mm,1); zzz:=BC*ttt; /*Now zzz is likely the closest vector in the lattice Gamma_C to yyy and min = |zzz-yyy|*/ DDD:=((R+1)^2 + S)^(1/2); //////////////////////////////////////////////////////////////////////// /* Construct the lattice Gamma_C.  The MAGMA function Lattice() assumes  Use the function EnumerationCost to compute an estimate the number of nodes in the tree to be visited during the execution of the algorithm that will enumerate all lattice vectors u with |u| \leq D + |y-z|.  The  number of nodes is essentially directly proportional to the time needed for the enumeration. If the number of nodes is too large for the enumration to be done in a reasonable amount of time, we increase C and try the reduction procedure again.  If several increases of C fail to result in a small enough  estimate for the number of nodes, then we abort the refined real reduction (there is no point in moving on to the next i0 in {1,...,s} because the uncondtional upper bound on A will not be improved). In Stehle and Watkins (2006), it is asserted that MAGMA’s enumeration algorithm has a traversal rate of about 7.5 millon nodes per second. Based on the examples in the MAGMA Handbook, the rate is appears to be 280  20 to 40 millon nodes per second. We will assume a traversal rate of 10 millon nodes per second.  Assuming we want the enumeration to take less  than 10 minutes, we want to abort if the estimated number of nodes is > 10*60*10^7 = 6000000000 Note: To MAGMA, Norm(v) = |v|^2. */ //////////////////////////////////////////////////////////////////////// GammaC:=Lattice(Transpose(BC)); if EnumerationCost(GammaC,RealField() ! (DDD+min)^2) gt 6000000000 then RunThroughNumber1+:=1;  //increase C and try again  ///// /* If increasing log(C) 20 times (with log(C) being increased 5% each time, so that log(C) will be double its original value) fails to produce a new conditional upper bound for A, then we abort the real reduction procedure. Also, print a message to the user indicating the refined real reduction procedure was unsuccesful for this reason. */ //// if RunThroughNumber1 eq 20 then print("Refined real reduction taking too long."); print("Case:"); iiii; print("i0:"); i0; JumpToEndOfRealReduction:=true; break i0; end if; else // EnumerationCost(GammaC,(DDD + min)^2) <= 6000000000 flag:=false; //ready to get out of while loop that increases C 281  //if necessary //////////////////////////////////////////////////////////////////////// /* Create a process P to enumerate all the vectors u in the lattice Gamma_C with lenght squared |u|^2 <= (D+|y-z|)^2 (equivalently length |u| <= D+|y-z|). To enumerate the vectors, we will need to repeatedly call NextVector(P). Callign NextVector(P) will return the next vector found in the enumeration (along with its norm). IsEmpty(P) returns true if the process P has finished enumerating all the vectors.  It returns false otherwise.  */ ////////////////////////////////////////////////////////////////////////// P:=ShortVectorsProcess(GammaC,Floor((DDD+min)^2)); ///////////////////////////////////////////////////////////////////////// /* Enumerate those lattice vectors u with |u| <= D+|y-z|, extract the corresponding tuples, and test those tuples. Extracted tuple = (b_{JJJ[2]},...,b_{JJJ[#JJJ]},b_{2+v+r}) bbb[i] = b_{JJJ[i]}, i=1 to #JJJ bbb[#JJJ+1] = b_{2+v+r} */ //////////////////////////////////////////////////////////////////////// bbb:=[RationalField() | ]; bbb[1]:=1; while not IsEmpty(P) do uuu:=NextVector(P);  282  //Extract tuple (b_{JJJ[2]},...,b_{JJJ[#JJJ]},b_{2+v+r}) for i:=2 to 1+#J do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; for i:=2+#J to #JJJ do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]))/W[JJJ[i]]; end for; sum:=0; for i:=1 to #JJJ do sum:=sum+bbb[i]*phi[JJJ[i]]; end for; bbb[#JJJ+1] := (uuu[#JJJ] - (yyy[#JJJ][1]-zzz[#JJJ][1]) - sum) /phi[2+v+r]; //Test the tuple passes:=true; while true do //this while loop is a hack to provide a way to //"jump to line X" for i:=2 to #JJJ do if not IsIntegral(bbb[i]) then passes:=false; break; end if; end for; if passes eq false then break; end if; if not IsIntegral((1/2)*bbb[#JJJ+1]) then passes:=false; break; end if;  for i:=2 to 1+#J do if bbb[i] gt B[JJJ[i]] or bbb[i] lt 0 then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2+#J to #JJJ do 283  if bbb[i] gt B[JJJ[i]] or bbb[i] lt -B[JJJ[i]] then passes:=false; break; end if; end for; if passes eq false then break; end if; if bbb[#JJJ+1] gt B[2+v+r] or bbb[#JJJ+1] lt -B[2+v+r] then passes:=false; break; end if; /*Test if the tuple fits in the new box.  If so, throw it away (it’s not  exceptional). */ FitsInTheNewBox:=true; for i:=2+#J to #JJJ do if Abs(bbb[i]) gt NewConditionalUpperBoundForAi0 then FitsInTheNewBox:=false; break i; end if; end for; if FitsInTheNewBox eq true then passes:=false; break; end if; for ll in I do LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[ll][JJJ[i]]; end for; if SpecialCase[ll] eq true then if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) ne bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; else //SpecialCase[ll] eq false if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) lt bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; end if; end for; 284  if passes eq false then break; end if; for ll in I do if SpecialCase[ll] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*beta[ll][JJJ[i]]; end for; if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDA) ne bbb[jl[ll]]*hh[ll] + Valuation(delta2[ll]) then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if;  break; end while; //end hack while loop /*If the tuple passes all the tests, add it to the list of exceptional tuples*/ if passes eq true then Remove(~bbb,#JJJ+1); Remove(~bbb,1); Include(~ExceptionalTuples, bbb); end if; // /*Since the enumeration process only spits out one of u and -u, we now need to do the same thing with -u.*/ uuu:=-uuu; //Extract tuple (b_{JJJ[2]},...,b_{JJJ[#JJJ]},b_{2+v+r})  285  for i:=2 to 1+#J do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]) + (1/2)*W[JJJ[i]]*B[JJJ[i]])/W[JJJ[i]]; end for; for i:=2+#J to #JJJ do bbb[i] := (uuu[i-1] - (yyy[i-1][1]-zzz[i-1][1]))/W[JJJ[i]]; end for; sum:=0; for i:=1 to #JJJ do sum:=sum+bbb[i]*phi[JJJ[i]]; end for; bbb[#JJJ+1] := (uuu[#JJJ] - (yyy[#JJJ][1]-zzz[#JJJ][1]) - sum) /phi[2+v+r]; //Test the tuple passes:=true; while true do //this while loop is a hack to provide a way to //"jump to line X" for i:=2 to #JJJ do if not IsIntegral(bbb[i]) then passes:=false; break; end if; end for; if passes eq false then break; end if; if not IsIntegral((1/2)*bbb[#JJJ+1]) then passes:=false; break; end if;  for i:=2 to 1+#J do if bbb[i] gt B[JJJ[i]] or bbb[i] lt 0 then passes:=false; break; end if; end for; if passes eq false then break; end if; for i:=2+#J to #JJJ do if bbb[i] gt B[JJJ[i]] or bbb[i] lt -B[JJJ[i]] then passes:=false; break; end if; 286  end for; if passes eq false then break; end if; if bbb[#JJJ+1] gt B[2+v+r] or bbb[#JJJ+1] lt -B[2+v+r] then passes:=false; break; end if; /*Test if the tuple fits in the new box.  If so, throw it away (it’s not  exceptional). */ FitsInTheNewBox:=true; for i:=2+#J to #JJJ do if Abs(bbb[i]) gt NewConditionalUpperBoundForAi0 then FitsInTheNewBox:=false; break i; end if; end for; if FitsInTheNewBox eq true then passes:=false; break; end if; for ll in I do LAMBDAprime:=0; for i:=1 to #JJJ do LAMBDAprime:=LAMBDAprime + bbb[i]*beta[ll][JJJ[i]]; end for; if SpecialCase[ll] eq true then if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) ne bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; else //SpecialCase[ll] eq false if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDAprime) lt bbb[jl[ll]]*hh[ll] + dd[ll] then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if;  287  for ll in I do if SpecialCase[ll] eq false then LAMBDA:=0; for i:=1 to #JJJ do LAMBDA:=LAMBDA + bbb[i]*beta[ll][JJJ[i]]; end for; if bbb[jl[ll]] gt (1/hh[ll])*(1/(p[ll]-1) - Valuation(delta2[ll])) and Valuation(LAMBDA) ne bbb[jl[ll]]*hh[ll] + Valuation(delta2[ll]) then passes:=false; break ll; end if; end if; end for; if passes eq false then break; end if;  break; end while; //end hack while loop /*If the tuple passes all the tests, add it to the list of exceptional tuples*/ if passes eq true then Remove(~bbb,#JJJ+1); Remove(~bbb,1); Include(~ExceptionalTuples, bbb); end if;  end while; //enumeration loop //Enumeration done ConditionalUpperBoundForA[i0]:=NewConditionalUpperBoundForAi0; end if; //end of IF controlled by EnumerationCost(GammaC,(DDD+min)^2) end if; /* end of IF controlled by NewConditionalUpperBoundForAi0 ge OldUnconditionalUpperBoundForA */ 288  end while; /* this is the while loop that increases log(C) if necessary, the while loop controlled by flag */  end for; //end i0 loop if JumpToEndOfRealReduction eq false then ///////////// /* Choose c11 to find an optimal i0-conditional upper bound for A for i0 in {s+1,...,s+2t} from Lemma 19.1 */ /////////// MIN:=UpperBoundForA; c11:=(1/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; 289  //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; c11:=((1000000 - 1)/1000000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; for i:=1 to 999 do c11:=(i/1000)*c10/(n-1); c15:=0; if t gt 0 then min:=Abs(Imaginary(thetaC[s+1])); for ii:=2 to t do j:=s-1 + 2*ii; if Abs(Imaginary(thetaC[j])) lt min then min:=Abs(Imaginary(thetaC[j])); end if; 290  end for; //end ii if Floor(-Log(min)/c11) gt 0 then c15:=Floor(-Log(min)/c11); end if; end if; max:=Ceiling((c8prime + c9prime*UpperBoundForN)/(c10-(n-1)*c11))-1; if max lt Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1 then max:=Ceiling((c8primeprime + c9primeprime*UpperBoundForN)/(c10-c11))-1; end if; if max lt c15 then max:=c15; end if; //now max is the upper bound for A in Lemma 19.1 if max lt MIN then MIN:=max; end if; end for;  //end i loop  //MIN is now an i0-conditional upper bound for A for i0 in {s+1,...,s+2t} ///// /* Compute the new unconditional bound for A */ ///// OldUpperBoundForA:=UpperBoundForA; NewUpperBoundForA:=Max([Max(ConditionalUpperBoundForA),MIN]); if NewUpperBoundForA lt OldUpperBoundForA then Improvement:=true; UpperBoundForA:=NewUpperBoundForA; for i:=1 to r do B[1+v+i]:=UpperBoundForA; end for; end if; end if; //controlled by JumpToEndOfRealReduction  291  if UpperBoundForA lt 0 then //there are no solutions to the current case of (11) continue iiii; end if;  end if; //end of IF for distinguishing (s>=3) (s=1,2) cases end if; //end of IF for s=0, s>=3, s=1or2 cases //done finding new upper bound for A UpperBoundForH:=Max([UpperBoundForN, UpperBoundForA]); print("Upperbounds for the n_l and A, respectively:"); UpperBoundForn; Floor(UpperBoundForA); end while;  //end loop for repeated refined reductions (the improvement //loop)  ///////////////////////////////////////////////////////////////////////// /* End Of Loop For Repeated Refined Reductions (the improvement loop) */ /////////////////////////////////////////////////////////////////////////  ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////// /////////////////////// /* Final Sieve (Section 22) 292  */ /////////////////////// ///////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// /* Compute NumberOfTuplesToCheck = the number of tuples to sieve through (excluding the [small number of] exceptional tuples) Select rational primes q_1,...q_k such that each q_i has at least three prime ideal factors in O_K that have residue degree one and such that the product q_1 ... q_k is > NumberOfTuplesToCheck For each q=q_h, pick three residue degree 1 prime ideal factors of q in O_K: qq_1, qq_2, qq_3.  For each  P_ij, E_ij from Section 22.  qq_i, we compute the integers m_i, A_i,  Actually, we compute these not as integers  but as elements in the finite field Z/qZ.  We store these elements in the  sequence Q[h][i]=[P_i1, ..., P_iv, E_i1, ..., E_ir, A_i, m_i] Q[h][i]=[P_{i,JJJ[2]-1}, ..., P_{i,JJJ[1+#J]-1}, E_i1, ..., E_ir, A_i, m_i] =[P_{i,J[1]}, ..., P_{i,J[#J]}, E_i1, ..., E_ir, A_i, m_i] We don’t store the primes q_1,...,q_k or their prime ideal factors.  */ ///////////////////////////////////////////////////////////////////////// NumberOfTuplesToCheck:=1; for i in J do NumberOfTuplesToCheck := NumberOfTuplesToCheck * (UpperBoundForn[i] + 1); end for; NumberOfTuplesToCheck := NumberOfTuplesToCheck * (2*UpperBoundForA + 1)^r; 293  ProductOfAllqSelected:=1; Q:=[**]; hhh:=0; j:=0; while ProductOfAllqSelected le NumberOfTuplesToCheck do ListOfPrimesInInterval:=PrimesInInterval(150*j+1,150*(j+1)); for i:=#ListOfPrimesInInterval to 1 by -1 do if ProductOfAllqSelected gt NumberOfTuplesToCheck then break i; end if; q:=ListOfPrimesInInterval[i]; DecompositionOfq:=Decomposition(OK,q); if #DecompositionOfq ge 3 then IndicesOfFirstThreeResidueDegreeOnePrimesAboveqEncountered:=[]; for ii:=1 to #DecompositionOfq do if InertiaDegree(DecompositionOfq[ii][1]) eq 1 then Append(~IndicesOfFirstThreeResidueDegreeOnePrimesAboveqEncountered,ii); end if; if #IndicesOfFirstThreeResidueDegreeOnePrimesAboveqEncountered eq 3 then break ii; end if; end for; //ii if #IndicesOfFirstThreeResidueDegreeOnePrimesAboveqEncountered eq 3 then hhh:=hhh+1; Q[hhh]:=[]; ProductOfAllqSelected:=ProductOfAllqSelected*q; ZmodqZ:=FiniteField(q, 1); for ii in IndicesOfFirstThreeResidueDegreeOnePrimesAboveqEncountered do temp:=[]; for jj:=1 to #J do temp[jj]:=ZmodqZ ! (pi[J[jj]][kk[J[jj]]] mod DecompositionOfq[ii][1]); end for; 294  for jj:=1 to r do temp[#J+jj]:=ZmodqZ ! (eps[jj] mod DecompositionOfq[ii][1]); end for; temp[1+#J+r]:=ZmodqZ ! ((OK ! alpha*zeta) mod DecompositionOfq[ii][1]); temp[2+#J+r]:=ZmodqZ ! ((OK ! theta) mod DecompositionOfq[ii][1]); Append(~Q[hhh],temp); end for; //ii end if;// controlled by //#IndicesOfFirstThreeResidueDegreeOnePrimesAboveqEncountered eq 3 end if;// controlled by #DecompositionOfq ge 3 end for; //i j:=j+1; end while;  ////////////////////////////////////////////////////////////////////////// /* Suppose bbb[i] = b_{JJJ[1+i]}, for i=1 to #JJJ-1. Note: bbb[i] = b_{JJJ[1+i]} = b_{1+J[i]}=n_{J[i]} for i:=1 to #J Note: bbb[#J+i] = b_{JJJ[1+#J+i]} = b_{1+v+i}=a_i for i:=1 to r We define BBBupper and BBBlower so that BBBlower[i] <= bbb[i] <= BBBupper[i] */ ///////////////////////////////////////////////////////////////////////// BBBupper:=[]; BBBlower:=[]; for i:=1 to #J do BBBupper[i]:=UpperBoundForn[J[i]]; BBBlower[i]:=0; end for; for i:=#J+1 to #J+r do 295  BBBupper[i]:=UpperBoundForA; BBBlower[i]:=-UpperBoundForA; end for;  //Solutions:=[]; ///////////////////////////////////////////////////////////////////////// /* Sieve through all tuples in the box defined by the bounds on the n_i (i in J) and the a_i */ ///////////////////////////////////////////////////////////////////////// print("Starting the sieve:"); count:=0; //used in SieveBox for testing.  Can be removed.  bbb:=[]; //needed for SieveBox() to work SieveBox(~bbb,~Solutions,~count,~BBBlower,~BBBupper,~Q,~J,~JJJ, ~ValueOfn,~kk,~hh,~ss,~tt,~ImageOfzetaC,~ImageOfalphaC,1); //////////////////////////////////////////////////////////////////////// /* Sieve through all exceptional tuples that we found in the refined reduction steps. After this procedure is done, Solutions will contain all the exceptional solutions (X,Y,z_1,...,z_v) of the sign-relaxed version of Thue-Mahler equation (1) that also satisfy the current case of (11). Recall:  Every solution of the Thue-Mahler equation satisfies some case  of (11). */ ///////////////////////////////////////////////////////////////////////// bbb:=[]; //ExceptionalTuples; 296  //ExceptionalTuplesTest[iiii]:=ExceptionalTuples; for i:=1 to #ExceptionalTuples do temp:=ExceptionalTuples[i]; for j:=1 to #temp do bbb[j]:=IntegerRing() ! temp[j]; end for;  //Test the tuple bbb for the congruences (25) passes:=true; for hhh:=1 to #Q do //test the tuple for the q=q_hhh congruence (25) CongruenceTest(~bbb,hhh,~passes,~Q,~J); if passes eq false then break hhh; end if; end for; if passes eq true then /* Use the tuple bbb (where bbb[i]=b_{JJJ[1+i]}, i=1 to #JJJ-1) to get the tuple bb (where bb[i] = b_{1+i}, i=1 to v).  Compute the  corresponding X,Y. Test if (X,Y,b_{2},...,b_{1+v}) gives a solution of the Thue-Mahler equation (1) and record the solution if so. */ ThueMahlerEquationTest(~bbb,~Solutions,~ImageOfzetaC,~ImageOfalphaC,~J, ~ValueOfn,~kk,~hh,~ss,~tt); end if; end for;  297  ////////////////////////////////////////////////////////////////////////// /* At this point almost all of the solutions of the sign-relaxed version of the Thue-Mahler equation have been found.  In the langauge of Section 6,  the ones we have found come from instances of (11) with \zeta equal to an element of T^{\prime}.  The missing ones come from instances of (11) with  \zeta equal to an element of $T \setminus T^{\prime}$.  The missing ones  are of the form (-x,-y,z_1,...,z_v) where (x,y,z_1,...,z_v) is a solution we have found. Now we find the missing solutions. */ ////////////////////////////////////////////////////////////////////////// SolutionsCopy:=Solutions; for ii:=1 to #SolutionsCopy do sol:=SolutionsCopy[ii]; //sol = (X,Y,z_1,...,z_v) sol[1]:=-sol[1]; sol[2]:=-sol[2]; //now sol = (-X,-Y,z_1,...,z_v) //Build RHS and LHS expressions RHSexpression:=a; for i:=1 to v do RHSexpression *:= p[i]^(sol[2+i]); end for; LHSexpression:= sol[1]^n + c[n]*sol[2]^n; for i:=1 to n-1 do LHSexpression:=LHSexpression + c[i]*sol[1]^(n-i)*sol[2]^i; end for; /*test if sol=(-X,-Y,z_1,...,z_v) is a solution of the Thue-Mahler equation (in the form Abs(LHSexpression)-Abs(RHSexpression) = 0).  If so,  append it to Solutions*/ if IsZero(Abs(LHSexpression)-Abs(RHSexpression)) then Include(~Solutions,sol); 298  end if; end for;  //SolutionsTest[iiii]:=Solutions; //print("Solutions of the sign-relaxed Thue-Mahler equation"); //Solutions;  ////////////////////////////////////////////////////////////////////////// /* At this point all the solutions of the sign-relaxed version of the Thue-Mahler equation have been found.  It is now a simple matter to go  through these solutions and eliminate the ones that are not solutions of the Thue-Mahler equation proper. Recall: Each element of Solutions is of the form [X,Y,z_1,...,z_v] */ ///////////////////////////////////////////////////////////////////////// SolutionsCopy:=Solutions; for ii:=#SolutionsCopy to 1 by -1 do //Build RHS and LHS expressions RHSexpression:=a; for i:=1 to v do RHSexpression *:= p[i]^(SolutionsCopy[ii][2+i]); end for; LHSexpression:= SolutionsCopy[ii][1]^n + c[n]*SolutionsCopy[ii][2]^n; for i:=1 to n-1 do LHSexpression:=LHSexpression + c[i]*SolutionsCopy[ii][1]^(n-i)*SolutionsCopy[ii][2]^i; end for; 299  /*test if =(X,Y,z_1,...,z_v) is a solution of the Thue-Mahler equation (in the form LHSexpression-RHSexpression = 0).  If not, remove it from  Solutions*/ if not IsZero(LHSexpression-RHSexpression) then Remove(~Solutions,ii); end if; end for;  print("Done case iiii="); iiii; ////////////////////////////////////////////////////////////////////////// end for;  //end iiii loop (the loop through the cases)  break PrecisionLoopVariable; end for; //end the precision loop //SolutionsTest; //ExceptionalTuplesTest; //Write("Solutions821.txt",SolutionsTest); print("Solutions of the Thue-Mahler equation:"); return Solutions; end function;  300  

Cite

Citation Scheme:

        

Citations by CSL (citeproc-js)

Usage Statistics

Share

Embed

Customize your widget with the following options, then copy and paste the code below into the HTML of your page to embed this item in your website.
                        
                            <div id="ubcOpenCollectionsWidgetDisplay">
                            <script id="ubcOpenCollectionsWidget"
                            src="{[{embed.src}]}"
                            data-item="{[{embed.item}]}"
                            data-collection="{[{embed.collection}]}"
                            data-metadata="{[{embed.showMetadata}]}"
                            data-width="{[{embed.width}]}"
                            async >
                            </script>
                            </div>
                        
                    
IIIF logo Our image viewer uses the IIIF 2.0 standard. To load this item in other compatible viewers, use this url:
http://iiif.library.ubc.ca/presentation/dsp.24.1-0072341/manifest

Comment

Related Items